Skip to content

Back to the catalog

flawed
github.comrepo

flawed

flawed is a static-analysis engine for Python web applications that builds a framework-aware model of an app's routes, request inputs, state effects, call graph, and value flow, exposing it both as a queryable Python library (open_repo(), load_findings()) and a CLI scanner. It runs pluggable rule modules (@detector contract) across three layers — L1 index, L2 semantic model, L3 rules — and outputs findings as JSON/SARIF with baseline diffing support for CI use.

TL;DR Open-source SAST engine that models Python web app routes/inputs/effects/call-graph for custom vulnerability rule authoring and SARIF-based scanning.
Document

What it is

flawed (Apache 2.0) is both a Python library and a CLI. The top-level flawed package is the analysis API — the same surface the bundled rules use — so you can drive the model from a REPL: open_repo() builds/loads a repo model, load_findings() reads back a prior --json/--sarif scan. Both return immutable, chainable collections (group_by / count_by / tabulate / | / slicing).

How it works

A scan runs three layers, named explicitly: L1 index + L2 semantic + L3 rules. L1 (extraction) is cached after the first run; later scans reuse it. Findings go to stdout; progress and diagnostics go to stderr. The route-query idiom the bundled auth-guard rule embodies is exposed directly, e.g.:

for route in repo.routes.accepting(POST):
    if route.reachable.effects() and not route.full_stack.checks():
        print(route)

Preconditions / Affected

Project tooling is via mise (task entry points) and uv (Python deps), pinned in mise.toml. New frameworks aren't automatic — teaching the engine one requires writing a provider (docs/, "Provider authoring") so rules see that framework's routes, inputs, and effects.

What to do

Setup and gate:

mise install   # Python + uv, pinned in mise.toml
mise deps      # uv sync --all-extras
mise run install-hooks   # version-controlled pre-commit gate
mise run check           # lockfile + lint + format + mypy + layers + tests

Scanning and custom rules:

flawed scan path/to/repo               # L1 + L2 + L3
flawed scan . --rules-dir ./my_rules   # your rules instead of built-ins

Note on the pre-commit hook: edit the tracked file at tools/hooks/pre-commit and reinstall — never edit the copy under .git/hooks/.

Caveats

Local observability is on by default. Every scan appends records — a runs.jsonl and a per-repo scan_metrics.jsonl under the data dir. The page states these are local-only (no network, no telemetry), but if you don't want them, set observability_enabled: false in ~/.config/flawed/config.yaml. Same file controls cache location (data_dir, repo_local; per-repo layout <data_dir>/owner__name/) and an opt-in, experimental mypy oracle (type_enrichment.enable_mypy_batch: false). Bare flawed prints an orientation dashboard and does not scan — use flawed . or flawed scan.

Technologies named here