> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myrqen.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Scan a Python app

> What the static pass understands in a FastAPI or Flask application, how to start the app so your agent can verify findings, and what is not covered.

Myrqen reads Python as well as JavaScript and TypeScript. Python is newer than the
JavaScript support and narrower: routes are modelled for **FastAPI** and **Flask** only.
You run it the same way, and you do not need Python installed for the static pass.

```bash theme={null}
npx myrqen@latest auto
```

A project with only `requirements.txt` (no `pyproject.toml`) is recognised as its own
root, so run the command from the directory that holds the app.

## What the static pass understands

| | FastAPI | Flask |
| - | - | - |
| Routes | `@app.get(...)` and the other method decorators, `api_route`, on `FastAPI` and `APIRouter` | `@app.route(...)` and the method shortcuts, on `Flask` and `Blueprint` |
| Prefixes | `APIRouter(prefix=...)` and `include_router(..., prefix=...)`, including mounts written in loops and app factories | `Blueprint(url_prefix=...)` and `register_blueprint(..., url_prefix=...)` |
| Caller input | Path, query, body and form parameters, typed by annotation. `int`, `Literal[...]` and constrained types are treated as clean where they cannot carry an injection | URL converters and the `request` proxy (`args`, `form`, `json`, `files`, `headers`, `cookies`) |
| Authentication | A `Depends(...)` or `Security(...)` dependency that resolves the caller, on the route or the router | `@login_required` and similar decorators, and `before_request` hooks on the blueprint or the app |

Data flow follows calls into this project's own functions and methods, across modules.
A route that passes a query value to a helper in another file is reported at the line
where the value reaches the sink, attributed to that route.

Findings use the same categories, reports, SARIF export and compliance mapping as
JavaScript findings. Python rule ids start with `py-`:

* Injection and unsafe input: SQL injection, command injection, path traversal,
  server-side request forgery, template injection, unsafe deserialisation (`pickle`,
  `yaml.load`), open redirect, reflected cross-site scripting.
* Configuration: hardcoded secrets, debug mode switched on unconditionally, session
  cookies without `HttpOnly`, `Secure` or `SameSite`.
* Access control: a route with no identity check beside authenticated siblings, and a
  record fetched by a caller-chosen id with no ownership check.

## Starting the app so findings can be verified

Static candidates stay **needs review** until your agent exercises them against the
running application. Myrqen detects how to start a Node app from `package.json`. For a
Python app it usually cannot, so the agent starts it, following the project's own
instructions first. Without instructions:

**FastAPI**

```bash theme={null}
uvicorn app.main:app --host 127.0.0.1 --port 8000
```

**Flask**

```bash theme={null}
flask --app app run --host 127.0.0.1 --port 5000
```

Use the project's virtual environment, bind to `127.0.0.1`, and do not switch on Flask's
debug mode. Save the command so the next run starts the same way (uvicorn binds to
`127.0.0.1:8000` by default):

```bash theme={null}
myrqen config set run.command "uvicorn app.main:app"
myrqen config set run.url 8000
```

## What is not covered

Each of these is also printed in the coverage notes of every report that parsed Python.

| Limit | Consequence |
| - | - |
| Django, Flask `MethodView` and other class-based views, plain Starlette, aiohttp, Tornado | The files are parsed and the configuration checks run, but handlers are not entry points, so no data-flow check starts from them. Your agent's own route mapping carries more of the assessment. |
| Dynamic dispatch, callbacks other than background tasks, threads and task queues, values kept in caches, decorators that rewrite a handler's arguments | Flows through them are not followed. A value one route stores in the session is followed to the routes that read it back. |
| Values stored in a database between requests | A value a route writes to a record's field is followed to unescaped markup (`Markup`, Jinja's `safe` filter) and template source that read the field back. Stored data reaching SQL, a shell, a path or a URL is not followed. |
| `requirements.txt`, `pyproject.toml`, `poetry.lock` | Python dependencies are not compared against advisories. |
| A hand-built `jinja2.Template(...)` with autoescaping off | Cross-site scripting through it is not followed. |

## How well it works

On 62 held-out FastAPI and Flask cases, written by an author who never read the Python
engine and scored once, recall was **0.774** and precision **0.923**, and 2 of 31
deliberately correct files drew a finding. That corpus has since been read and fixed
against, so this is the most recent blind Python figure, not a measurement of the current
engine; the next one waits on a new held-out set. Those cases cover only the vulnerability
classes the Python engine was built to find. The figure says how well that scope is
covered, not how much of a Python application is, so it is not comparable with the
JavaScript figure. The figures, and what was missed, are on
[Benchmark](/guides/benchmark) and [myrqen.cc/benchmarks](https://myrqen.cc/benchmarks).

A report with no findings is not evidence that an application is secure.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.