| name | pyre-type-analysis |
| description | Facebook Pyre static type analysis patterns for Python. Incremental type checking, taint tracking for data-flow security analysis, pysa rules, and integrating Pyre into CI pipelines. Sources: facebook/pyre-check (MIT). |
/pyre-type-analysis
When to Use
- Large Python codebases where mypy is too slow or lacks taint analysis
- Security audits: trace untrusted input (HTTP params) to sinks (SQL, shell, eval)
- Incremental type checking in CI without full re-analysis on every commit
- Data flow analysis: detect secrets leaking into log statements
Do NOT use for
- JavaScript/TypeScript (use [[eslint-rule-engine]] or [[ts-morph-refactor]])
- Simple type hints (mypy is sufficient for small projects)
.pyre_configuration
{
"site_package_search_strategy": "all",
"source_directories": ["src"],
"exclude": ["**/tests/**", "**/migrations/**"],
"strict": true,
"workers": 4,
"typeshed": null
}
Run incremental check
pyre start
pyre check
pyre incremental
pyre stop
Pysa taint analysis — source/sink model
def flask.Request.args.__getitem__(self, key: str) -> TaintedString: ...
def flask.Request.form.__getitem__(self, key: str) -> TaintedString: ...
def os.environ.__getitem__(self, key: str) -> TaintedString: ...
def subprocess.run(args: TaintSink[RemoteCodeExecution], ...): ...
def os.system(command: TaintSink[RemoteCodeExecution]): ...
def logging.Logger.info(msg: TaintSink[Logging], *args): ...
{
"sources": [{ "name": "TaintedString" }],
"sinks": [
{ "name": "RemoteCodeExecution" },
{ "name": "Logging" }
],
"rules": [
{
"name": "User-controlled data flows to shell command",
"code": 5001,
"sources": ["TaintedString"],
"sinks": ["RemoteCodeExecution"],
"message_format": "Untrusted input from {$sources} reaches {$sinks}"
}
]
}
Run pysa security analysis
pyre analyze \
--taint-models-path stubs/taint \
--output-format sarif \
> pyre-findings.sarif
jq '.runs[].results[] | select(.level == "error")' pyre-findings.sarif
Python type annotation patterns Pyre enforces
from typing import Optional, Union
def process(user_id: Optional[str]) -> dict[str, int]:
if user_id is None:
return {}
return {"id": int(user_id)}
def handle(value: str | int) -> str:
if isinstance(value, str):
return value.upper()
return str(value)
Anti-Fake-Pass Checklist
❌ pyre start not run before pyre check → no background server, check fails
❌ Missing .pyre_configuration → Pyre analyzes wrong directories
❌ strict: false in config → Optional not enforced, many type errors silently ignored
❌ Pysa without .pysa stubs → taint analysis finds nothing (no source/sink model)
❌ TaintedString applied too broadly → every string becomes a taint source; false positives flood output
❌ SARIF output not parsed → raw JSON misread as all-pass