Static analysis engine for Python web applications
Project description
flawed
A static-analysis engine for Python web applications. flawed builds a framework-aware model of a Python web app — its routes, request inputs, state effects, call graph, and value flow — and exposes that model as a Python library and a command-line tool.
Python API
The top-level flawed package is the analysis API — the same surface the
bundled rules are built on, usable directly from a REPL or a script.
open_repo() loads a repository's model:
from flawed import open_repo
from flawed.route import POST
repo = open_repo("path/to/app") # build (or load cached) the model
repo.routes # RouteCollection(75) [Route(GET / → index, …), …]
repo.routes.count_by(lambda r: "/".join(sorted(m.name for m in r.methods)))
# Counter({'GET': 35, 'POST': 28, 'GET/POST': 12, ...})
# Which POST routes write state but declare no guard in their handler stack?
for route in repo.routes.accepting(POST):
if route.reachable.effects() and not route.full_stack.checks():
print(route)
load_findings() is its mirror image — comb through a scan you already ran:
from flawed import load_findings
findings = load_findings("scan.json") # a --json or --sarif capture
findings.count_by("rule_id").most_common(5) # which rules fired most
findings.min_severity("high").in_dir("auth/") # high-sev findings under auth/
findings.diff(load_findings("baseline.json")).added # new findings vs a baseline
Both return immutable, chainable collections (group_by / count_by /
tabulate / | / slicing). See Python API for the full
surface.
Command line
flawed is also a command-line scanner that runs rule modules over a repository:
flawed # orientation dashboard (does not scan)
flawed . # scan the current directory
flawed scan path/to/repo # scan a repository: L1 index + L2 semantic + L3 rules
flawed scan . --rules-dir ./my_rules # run your own rule modules instead of the built-ins
Findings stream to stdout, progress and diagnostics to stderr. See
CLI for output formats (--json, --sarif), exit codes,
baseline diffing, and the full command list.
Documentation
End-user docs live in docs/:
- Writing rules — the rule-authoring guide: the
@detectorcontract, the objects a rule navigates, and running your own rules with--rules-dir. - The analysis model — what the engine models (routes, inputs, effects, call graph, value flow) and how to think about it.
- CLI — running scans, output formats, and configuration.
- Python API — querying the model interactively from a REPL or script.
- Provider authoring — teaching the engine a new framework so your rules see its routes, inputs, and effects.
Setup
flawed uses mise for project tools and task entry points, and uv for Python
dependency resolution.
mise install # Python + uv, pinned in mise.toml
mise deps # uv sync --all-extras
Development
mise run install-hooks # install the version-controlled pre-commit gate
mise run check # full gate: lockfile + lint + format + mypy + layers + framework/dep/subprocess checks + tests
mise run check -- PATH... # scope the gate to specific files or directories
mise run test # run affected tests (testmon)
mise run test -- tests/unit/ # scope tests to a directory or file
The pre-commit hook is tracked at tools/hooks/pre-commit; mise run install-hooks copies it into the repository's git hooks directory (idempotent,
and worktree-aware). Edit the tracked file and reinstall — never edit the copy
under .git/hooks/ directly.
Configuration
Global config: ~/.config/flawed/config.yaml
data_dir: <path> # where L1 cache artifacts are stored
repo_local: false # true = store cache next to each repo
observability_enabled: true # local run/scan metrics; set false to opt out
type_enrichment:
enable_mypy_batch: false # opt-in experimental mypy oracle
By default each scan appends local observability records — a runs.jsonl plus a
per-repo scan_metrics.jsonl under the data dir. These are written locally
only (no network, no telemetry); set observability_enabled: false to turn
them off.
Per-repo cache uses <data_dir>/owner__name/ layout. The index is cached after
the first run; subsequent scans skip L1 extraction.
License
flawed is released under the Apache License 2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flawed-0.7.2.tar.gz.
File metadata
- Download URL: flawed-0.7.2.tar.gz
- Upload date:
- Size: 562.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4492cc1d8926a1ddb79dae6a1a6d613071c2cb0b7ec4190c4e0dffdea8905662
|
|
| MD5 |
03c36dc43aedbfea98748c259a070596
|
|
| BLAKE2b-256 |
bb514b8fb5f2492c834e01b02d7c78a5315f3ce1eda6babb8c4faeb8a6a42157
|
Provenance
The following attestation bundles were made for flawed-0.7.2.tar.gz:
Publisher:
publish.yml on execveat/flawed
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flawed-0.7.2.tar.gz -
Subject digest:
4492cc1d8926a1ddb79dae6a1a6d613071c2cb0b7ec4190c4e0dffdea8905662 - Sigstore transparency entry: 1741016947
- Sigstore integration time:
-
Permalink:
execveat/flawed@89106b9aab6d9561e6b395607716b94762834d71 -
Branch / Tag:
refs/tags/v0.7.2 - Owner: https://github.com/execveat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@89106b9aab6d9561e6b395607716b94762834d71 -
Trigger Event:
release
-
Statement type:
File details
Details for the file flawed-0.7.2-py3-none-any.whl.
File metadata
- Download URL: flawed-0.7.2-py3-none-any.whl
- Upload date:
- Size: 675.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f0ad360b9c8ff4d82284e5cff2e1fa81fed3500d3c3c6ec5c559a96da1facfc
|
|
| MD5 |
bb2253851152f731062450fd60e802d9
|
|
| BLAKE2b-256 |
f489e9b312f76d69fead727d7c6c0af52b204acb1061cfb5950c56697daee588
|
Provenance
The following attestation bundles were made for flawed-0.7.2-py3-none-any.whl:
Publisher:
publish.yml on execveat/flawed
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flawed-0.7.2-py3-none-any.whl -
Subject digest:
0f0ad360b9c8ff4d82284e5cff2e1fa81fed3500d3c3c6ec5c559a96da1facfc - Sigstore transparency entry: 1741017001
- Sigstore integration time:
-
Permalink:
execveat/flawed@89106b9aab6d9561e6b395607716b94762834d71 -
Branch / Tag:
refs/tags/v0.7.2 - Owner: https://github.com/execveat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@89106b9aab6d9561e6b395607716b94762834d71 -
Trigger Event:
release
-
Statement type: