flawed 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flawed-0.0.1/.gitignore +12 -0
- flawed-0.0.1/PKG-INFO +4 -0
- flawed-0.0.1/README.md +25 -0
- flawed-0.0.1/docs/architecture-overview.md +131 -0
- flawed-0.0.1/docs/architecture.md +330 -0
- flawed-0.0.1/docs/boundaries.md +294 -0
- flawed-0.0.1/docs/code-index.md +708 -0
- flawed-0.0.1/docs/principles.md +274 -0
- flawed-0.0.1/docs/rule-api.md +351 -0
- flawed-0.0.1/docs/semantic-layer.md +653 -0
- flawed-0.0.1/docs/tooling-survey.md +674 -0
- flawed-0.0.1/examples/cve/README.md +8 -0
- flawed-0.0.1/examples/oop_style/README.md +123 -0
- flawed-0.0.1/examples/oop_style/base.py +359 -0
- flawed-0.0.1/examples/oop_style/rules.py +296 -0
- flawed-0.0.1/examples/oop_style/showcase.py +247 -0
- flawed-0.0.1/examples/ucl/README.md +8 -0
- flawed-0.0.1/npm/index.js +4 -0
- flawed-0.0.1/npm/package.json +12 -0
- flawed-0.0.1/pyproject.toml +42 -0
- flawed-0.0.1/src/flawed/__init__.py +43 -0
- flawed-0.0.1/src/flawed/calls.py +202 -0
- flawed-0.0.1/src/flawed/checks.py +166 -0
- flawed-0.0.1/src/flawed/collections.py +317 -0
- flawed-0.0.1/src/flawed/conditions.py +120 -0
- flawed-0.0.1/src/flawed/core.py +127 -0
- flawed-0.0.1/src/flawed/detector.py +52 -0
- flawed-0.0.1/src/flawed/effects.py +258 -0
- flawed-0.0.1/src/flawed/evidence.py +125 -0
- flawed-0.0.1/src/flawed/flow.py +148 -0
- flawed-0.0.1/src/flawed/function.py +224 -0
- flawed-0.0.1/src/flawed/inputs.py +305 -0
- flawed-0.0.1/src/flawed/repo.py +92 -0
- flawed-0.0.1/src/flawed/route.py +203 -0
- flawed-0.0.1/src/flawed/scopes.py +204 -0
- flawed-0.0.1/tests/__init__.py +0 -0
- flawed-0.0.1/tests/fixtures/apps/classes/models.py +43 -0
- flawed-0.0.1/tests/fixtures/apps/decorators/app.py +53 -0
- flawed-0.0.1/tests/fixtures/apps/flask_basic/app.py +47 -0
- flawed-0.0.1/tests/fixtures/apps/functions/helpers.py +11 -0
- flawed-0.0.1/tests/fixtures/apps/functions/main.py +39 -0
- flawed-0.0.1/tests/fixtures/apps/imports/__init__.py +1 -0
- flawed-0.0.1/tests/fixtures/apps/imports/helpers.py +13 -0
- flawed-0.0.1/tests/fixtures/apps/imports/main.py +16 -0
- flawed-0.0.1/tests/fixtures/apps/minimal/app.py +8 -0
- flawed-0.0.1/tests/specs/__init__.py +0 -0
- flawed-0.0.1/tests/specs/basics/__init__.py +0 -0
- flawed-0.0.1/tests/specs/basics/test_call_graph.py +71 -0
- flawed-0.0.1/tests/specs/basics/test_cfg.py +50 -0
- flawed-0.0.1/tests/specs/basics/test_class_discovery.py +65 -0
- flawed-0.0.1/tests/specs/basics/test_decorator_discovery.py +57 -0
- flawed-0.0.1/tests/specs/basics/test_function_discovery.py +184 -0
- flawed-0.0.1/tests/specs/basics/test_imports_resolution.py +36 -0
- flawed-0.0.1/tests/specs/basics/test_scoped_queries.py +88 -0
- flawed-0.0.1/tests/specs/basics/test_value_flow.py +78 -0
- flawed-0.0.1/tests/specs/conftest.py +8 -0
- flawed-0.0.1/tests/specs/detection/__init__.py +0 -0
- flawed-0.0.1/tests/specs/exploration/__init__.py +0 -0
- flawed-0.0.1/tests/unit/__init__.py +0 -0
- flawed-0.0.1/tests/unit/test_detector.py +24 -0
- flawed-0.0.1/tests/unit/test_enums.py +68 -0
- flawed-0.0.1/tests/unit/test_evidence.py +58 -0
- flawed-0.0.1/tests/unit/test_imports.py +187 -0
- flawed-0.0.1/tests/unit/test_instantiation.py +175 -0
- flawed-0.0.1/tests/unit/test_selectors.py +228 -0
- flawed-0.0.1/tests/unit/test_type_relationships.py +102 -0
flawed-0.0.1/.gitignore
ADDED
flawed-0.0.1/PKG-INFO
ADDED
flawed-0.0.1/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# flawed
|
|
2
|
+
|
|
3
|
+
Static analysis engine for confusion vulnerability research in Python web applications.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from flawed import open_repo, detector
|
|
7
|
+
from flawed.inputs import Query, Form, Json
|
|
8
|
+
from flawed.effects import Mutation, Session
|
|
9
|
+
from flawed.checks import Crypto, Token
|
|
10
|
+
from flawed.route import Route, POST, accepting
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Status
|
|
14
|
+
|
|
15
|
+
Early development. API contracts are defined; engine runtime is not yet implemented.
|
|
16
|
+
|
|
17
|
+
## Structure
|
|
18
|
+
|
|
19
|
+
- `src/flawed/` — Rule API (Layer 3) — the primary user-facing surface
|
|
20
|
+
- `src/flawed/semantic/` — Semantic Layer (Layer 2) — framework interpretation (planned)
|
|
21
|
+
- `src/flawed/index/` — Code Index (Layer 1) — structural extraction (planned)
|
|
22
|
+
|
|
23
|
+
## Design
|
|
24
|
+
|
|
25
|
+
See `docs/` for architecture and design documents.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Confusion Analysis Engine
|
|
2
|
+
|
|
3
|
+
Specification for the standalone analysis engine for researching confusion
|
|
4
|
+
vulnerabilities in Python web applications.
|
|
5
|
+
|
|
6
|
+
## Problem Statement
|
|
7
|
+
|
|
8
|
+
> Given a local repository snapshot, compile source code into stable
|
|
9
|
+
> structural facts, interpretable framework-specific domain objects, and
|
|
10
|
+
> composable detection-rule primitives for confusion vulnerability research.
|
|
11
|
+
|
|
12
|
+
## Architecture
|
|
13
|
+
|
|
14
|
+
Three layers. Each owns a distinct concern. Dependencies flow in one
|
|
15
|
+
direction: Layer 3 -> Layer 2 -> Layer 1. No skipping, no reverse.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
repository snapshot
|
|
19
|
+
|
|
|
20
|
+
v
|
|
21
|
+
Layer 1: Code Index
|
|
22
|
+
Python-generic structural extraction.
|
|
23
|
+
Runs once per repo snapshot. Persists artifacts.
|
|
24
|
+
Exposes: functions, classes, call graph, CFGs, value-flow,
|
|
25
|
+
symbols, decorators, imports, class hierarchy.
|
|
26
|
+
|
|
|
27
|
+
| CodeIndex API (frozen Python objects)
|
|
28
|
+
v
|
|
29
|
+
Layer 2: Semantic Layer
|
|
30
|
+
Framework/library/convention interpretation.
|
|
31
|
+
Runs per detection. Extensible by users.
|
|
32
|
+
Exposes: routes, request reads, gates, effects,
|
|
33
|
+
lifecycle hooks, on-demand flow traces.
|
|
34
|
+
|
|
|
35
|
+
| WebApp API (frozen domain objects)
|
|
36
|
+
v
|
|
37
|
+
Layer 3: Rule API
|
|
38
|
+
Typed domain navigation, scoped queries,
|
|
39
|
+
evidence building, detector framework, dev tools.
|
|
40
|
+
Consumers: rule authors, notebooks, batch detection.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Directory Structure
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
L6/
|
|
47
|
+
README.md <- You are here
|
|
48
|
+
principles.md <- Vision, non-negotiable principles, API design principles
|
|
49
|
+
architecture.md <- Three-layer overview, data flow, execution model
|
|
50
|
+
boundaries.md <- Normative boundary spec: what belongs where
|
|
51
|
+
|
|
52
|
+
API-L1-Code-Index/ <- Layer 1: Python-generic structural extraction
|
|
53
|
+
README.md Extraction pipeline, CodeIndex API, data types
|
|
54
|
+
|
|
55
|
+
API-L2-Semantic-Layer/ <- Layer 2: Framework/library interpretation
|
|
56
|
+
README.md Interpreter architecture, WebApp API, flow tracing
|
|
57
|
+
|
|
58
|
+
API-L3-Rule-API/ <- Layer 3: Rule authoring and exploration surface
|
|
59
|
+
README.md Domain objects, queries, evidence, detector framework
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Reading Order
|
|
63
|
+
|
|
64
|
+
### For rule authors (start here)
|
|
65
|
+
|
|
66
|
+
1. `principles.md` sections 1-3 -- vision and API design principles
|
|
67
|
+
2. `API-L3-Rule-API/README.md` -- domain objects, queries, examples
|
|
68
|
+
3. Start writing rules
|
|
69
|
+
|
|
70
|
+
### For framework adapter authors
|
|
71
|
+
|
|
72
|
+
1. `principles.md` -- non-negotiable design principles
|
|
73
|
+
2. `boundaries.md` -- what belongs in which layer
|
|
74
|
+
3. `API-L2-Semantic-Layer/README.md` -- interpreter protocol, extension model
|
|
75
|
+
|
|
76
|
+
### For pipeline developers
|
|
77
|
+
|
|
78
|
+
1. `principles.md` -- full document
|
|
79
|
+
2. `architecture.md` -- three-layer overview, data flow, execution model
|
|
80
|
+
3. `boundaries.md` -- normative boundary spec
|
|
81
|
+
4. `API-L1-Code-Index/README.md` -- extraction pipeline, CodeIndex API
|
|
82
|
+
5. `API-L2-Semantic-Layer/README.md` -- interpreter architecture, WebApp API
|
|
83
|
+
6. `API-L3-Rule-API/README.md` -- rule authoring surface
|
|
84
|
+
|
|
85
|
+
## Key Design Decisions
|
|
86
|
+
|
|
87
|
+
1. **Framework knowledge is never in the run-once pipeline.** The Code
|
|
88
|
+
Index knows Python the language. Flask, SQLAlchemy, marshmallow, and
|
|
89
|
+
every other framework live exclusively in the Semantic Layer.
|
|
90
|
+
|
|
91
|
+
2. **Extensibility without re-extraction.** Adding a new framework,
|
|
92
|
+
fixing a route-detection pattern, or recognizing a new ORM call
|
|
93
|
+
requires zero re-extraction. User extensions have full parity with
|
|
94
|
+
built-in defaults.
|
|
95
|
+
|
|
96
|
+
3. **On-demand flow tracing replaces pre-computed taint.** Semgrep's
|
|
97
|
+
taint signatures are removed from the internal pipeline. Data-flow
|
|
98
|
+
tracing is a runtime Semantic Layer service that accepts arbitrary
|
|
99
|
+
sources, not just `request`.
|
|
100
|
+
|
|
101
|
+
4. **Decorators split: syntax in Layer 1, meaning in Layer 2.** The Code
|
|
102
|
+
Index records decorator name, arguments, and location. The Semantic
|
|
103
|
+
Layer decides whether a decorator is an auth gate, a route
|
|
104
|
+
registration, or a CSRF exemption.
|
|
105
|
+
|
|
106
|
+
5. **Strict unidirectional layering.** Layer 3 -> Layer 2 -> Layer 1.
|
|
107
|
+
No skipping. No reverse dependencies. No exceptions.
|
|
108
|
+
|
|
109
|
+
## Supersession
|
|
110
|
+
|
|
111
|
+
This directory supersedes `wip/round2/L5/confusion-analysis/`.
|
|
112
|
+
|
|
113
|
+
What changed from L5 to L6:
|
|
114
|
+
|
|
115
|
+
| L5 | L6 | Why |
|
|
116
|
+
|----|-----|-----|
|
|
117
|
+
| 7-stage monolithic pipeline | 3-layer architecture | Clear responsibility boundaries, strict layering |
|
|
118
|
+
| Flask-specific extraction in run-once pipeline | All framework logic in Semantic Layer | Extensibility without re-extraction |
|
|
119
|
+
| No middle layer | Semantic Layer (Layer 2) | Framework interpretation must be dynamic and extensible |
|
|
120
|
+
| Pre-computed taint via Semgrep rule | On-demand flow tracing at Layer 2 | Arbitrary sources, not just `request`; no Semgrep dependency |
|
|
121
|
+
| Extension via model libraries only | Full interpreter replacement/extension | First-class framework adapter protocol |
|
|
122
|
+
| Mixed generic/Flask components per stage | Pure generic pipeline + pure framework layer | Each layer testable in isolation |
|
|
123
|
+
|
|
124
|
+
## Relationship to Other Documentation
|
|
125
|
+
|
|
126
|
+
| Document | Role |
|
|
127
|
+
|----------|------|
|
|
128
|
+
| `wip/round2/L5/confusion-analysis/` | Previous iteration (superseded by this directory) |
|
|
129
|
+
| `wip/round2/L4/confusion-analysis-pipeline.md` | Historical: original monolithic spec |
|
|
130
|
+
| `docs/analysis-pipeline/` | Empirical research: Semgrep capabilities, tool evaluations |
|
|
131
|
+
| `.claude/scratch/semgrep-pro-investigation/` | Research artifacts: extraction outputs, wave test results |
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Three layers. Each owns a distinct concern. Dependencies flow in one
|
|
4
|
+
direction: Layer 3 → Layer 2 → Layer 1. No skipping, no reverse references.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
repository snapshot
|
|
8
|
+
│
|
|
9
|
+
▼
|
|
10
|
+
┌─────────────────────────────────────────────┐
|
|
11
|
+
│ Layer 1: Code Index │
|
|
12
|
+
│ Python-generic structural extraction. │
|
|
13
|
+
│ Runs once per repo snapshot. │
|
|
14
|
+
│ Persists artifacts to disk. │
|
|
15
|
+
│ Exposes a typed Python API over the │
|
|
16
|
+
│ pre-computed code structure. │
|
|
17
|
+
│ │
|
|
18
|
+
│ Produces: AST entities, call graph, CFGs, │
|
|
19
|
+
│ value-flow, symbols, class hierarchy, │
|
|
20
|
+
│ imports, decorators, attribute accesses. │
|
|
21
|
+
└────────────────────┬────────────────────────┘
|
|
22
|
+
│ CodeIndex API (Python objects, frozen)
|
|
23
|
+
▼
|
|
24
|
+
┌─────────────────────────────────────────────┐
|
|
25
|
+
│ Layer 2: Semantic Layer │
|
|
26
|
+
│ Framework/library/convention-specific │
|
|
27
|
+
│ interpretation. Runs per detection. │
|
|
28
|
+
│ Extensible by rule authors. │
|
|
29
|
+
│ │
|
|
30
|
+
│ Produces: Routes, RequestReads, Gates, │
|
|
31
|
+
│ Effects, Lifecycle, method branches, │
|
|
32
|
+
│ classified mutations, enhanced dispatch, │
|
|
33
|
+
│ on-demand data-flow traces. │
|
|
34
|
+
└────────────────────┬────────────────────────┘
|
|
35
|
+
│ WebApp API (domain objects, frozen)
|
|
36
|
+
▼
|
|
37
|
+
┌─────────────────────────────────────────────┐
|
|
38
|
+
│ Layer 3: Rule API │
|
|
39
|
+
│ Typed domain navigation, scoped queries, │
|
|
40
|
+
│ collection API, evidence building, │
|
|
41
|
+
│ detector framework, dev tools. │
|
|
42
|
+
│ │
|
|
43
|
+
│ Consumers: rule authors, notebooks, │
|
|
44
|
+
│ interactive exploration, batch detection. │
|
|
45
|
+
└─────────────────────────────────────────────┘
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Layer 1: Code Index
|
|
51
|
+
|
|
52
|
+
### Responsibility
|
|
53
|
+
|
|
54
|
+
Given a local Python repository snapshot, extract structural facts that are
|
|
55
|
+
true of the code itself, independent of any web framework, library, or
|
|
56
|
+
coding convention. Store those facts. Expose them through a typed Python API
|
|
57
|
+
that hides file layout, serialization format, and internal ID schemes.
|
|
58
|
+
|
|
59
|
+
### What it produces
|
|
60
|
+
|
|
61
|
+
| Fact kind | Source | Notes |
|
|
62
|
+
|-----------|--------|-------|
|
|
63
|
+
| Functions | LibCST + astroid | name, FQN, params, location, kind (top-level/method/nested/lambda) |
|
|
64
|
+
| Classes | LibCST + astroid | name, FQN, bases, location, MRO, hierarchy |
|
|
65
|
+
| Imports | LibCST + Semgrep symbols | resolved names, aliases, re-exports |
|
|
66
|
+
| Decorators | LibCST + astroid | name, resolved FQN, args, target function, location — no semantic interpretation |
|
|
67
|
+
| Call edges | Semgrep call graph + AST | merged cross-file, per-file, with resolution status; includes unresolved dispatch patterns (getattr, dict dispatch) as edges |
|
|
68
|
+
| CFGs | LibCST + NetworkX | per-function blocks, edges, dominance, branch structure |
|
|
69
|
+
| Value-flow edges | LibCST + astroid + Semgrep svalues | assignments, arguments, returns, aliases, unpacking |
|
|
70
|
+
| Symbol resolution | LibCST + astroid + Semgrep symbols | FQNs, resolved names, import chains |
|
|
71
|
+
| Class hierarchy | LibCST + astroid | MRO, base classes, method resolution — stored on Class objects |
|
|
72
|
+
| Attribute accesses | LibCST + astroid | reads and writes on any object; includes dict operations, list/set mutations, del statements |
|
|
73
|
+
| Source locations | all passes | file, line, column for every fact |
|
|
74
|
+
| Errors and gaps | all passes | per-file parse failures, per-function CFG failures, unresolved symbols |
|
|
75
|
+
|
|
76
|
+
### What it does NOT produce
|
|
77
|
+
|
|
78
|
+
- Routes or endpoint registrations.
|
|
79
|
+
- Request input classifications (`Query`, `Form`, `Json`).
|
|
80
|
+
- Security gate or effect observations.
|
|
81
|
+
- Lifecycle hooks or framework state access.
|
|
82
|
+
- Taint summaries or request-data flow traces.
|
|
83
|
+
- Semantic tags (`auth_gate`, `db_write`, `lifecycle_state`).
|
|
84
|
+
- Anything that requires knowing which framework the code uses.
|
|
85
|
+
|
|
86
|
+
### API shape
|
|
87
|
+
|
|
88
|
+
Layer 1 exposes a `CodeIndex` object. All access goes through it. No
|
|
89
|
+
consumer reads JSONL files, raw Semgrep output, or internal indexes
|
|
90
|
+
directly.
|
|
91
|
+
|
|
92
|
+
Built on mandatory dependencies: LibCST (parsing, scope analysis), astroid
|
|
93
|
+
(inference, MRO), Semgrep Pro (cross-file call graph, symbols), basedpyright
|
|
94
|
+
(type oracle), and NetworkX (graph algorithms).
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
idx = CodeIndex.open("/path/to/analysis-store/repos/slug/snapshot")
|
|
98
|
+
|
|
99
|
+
idx.functions # FunctionCollection — filter, iterate, lookup by FQN
|
|
100
|
+
idx.classes # ClassCollection — includes hierarchy (MRO, subclasses)
|
|
101
|
+
idx.imports # ImportCollection
|
|
102
|
+
idx.decorators # DecoratorCollection — syntactic facts with resolved FQNs
|
|
103
|
+
idx.call_graph # CallGraph — nodes, edges, reachability; includes
|
|
104
|
+
# unresolved dispatch edges (getattr, dict dispatch)
|
|
105
|
+
idx.cfg(fn_fqn) # per-function CFG with dominance
|
|
106
|
+
idx.value_flow # ValueFlowGraph — assignment chains, argument binding
|
|
107
|
+
idx.symbols # SymbolIndex — FQN resolution, import chains
|
|
108
|
+
idx.attributes # AttributeAccessCollection — reads/writes/mutations on any object
|
|
109
|
+
idx.source(location) # source text for a location
|
|
110
|
+
idx.errors # extraction errors and gaps
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Every object returned is frozen. Layer 2 cannot mutate Layer 1 data.
|
|
114
|
+
|
|
115
|
+
### Execution
|
|
116
|
+
|
|
117
|
+
Runs once per repository snapshot via CLI. Produces a deterministic artifact
|
|
118
|
+
tree in the analysis store. Idempotent: re-running with the same source and
|
|
119
|
+
tool versions produces identical output.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Layer 2: Semantic Layer
|
|
124
|
+
|
|
125
|
+
### Responsibility
|
|
126
|
+
|
|
127
|
+
Interpret Layer 1's Python-structural facts through the lens of a specific
|
|
128
|
+
web framework, set of libraries, and project conventions. Produce typed
|
|
129
|
+
domain objects that encode what the code *means* in a web application
|
|
130
|
+
security context.
|
|
131
|
+
|
|
132
|
+
This is where all framework-specific knowledge lives. Flask route
|
|
133
|
+
registration patterns, request container mappings, ORM write detection,
|
|
134
|
+
session and context state identification, lifecycle hooks — all of it.
|
|
135
|
+
|
|
136
|
+
### What it produces
|
|
137
|
+
|
|
138
|
+
| Domain concept | Built from (Layer 1 facts) | Framework knowledge required |
|
|
139
|
+
|----------------|---------------------------|------------------------------|
|
|
140
|
+
| Routes | decorators + functions + class hierarchy | Route registration patterns (`@app.route`, MethodView, etc.) |
|
|
141
|
+
| Request reads | call sites + symbol resolution + attribute accesses | Request container API (`request.args.get`, marshmallow schema, etc.) |
|
|
142
|
+
| Context accesses | attribute accesses + import resolution | Context proxies (`g`, `session`, `current_user`) |
|
|
143
|
+
| Gates | decorators + call sites + conditionals | Auth decorator patterns, permission check functions |
|
|
144
|
+
| Effects | call sites + attribute writes + symbol resolution | ORM write patterns, external request patterns |
|
|
145
|
+
| Lifecycle hooks | decorators + functions + import resolution | Hook registration (`before_request`, `after_request`) |
|
|
146
|
+
| Method branches | CFG blocks + conditionals + value-flow | Method dispatch patterns (`request.method == "POST"`) |
|
|
147
|
+
| Classified mutations | attribute accesses + symbol resolution | Framework-specific state mutation patterns |
|
|
148
|
+
| Enhanced dispatch | call graph (unresolved edges) + class hierarchy | Framework-specific dispatch (MethodView, signals) |
|
|
149
|
+
| On-demand flow traces | call graph + value-flow + CFGs | Source/sink definitions, propagation rules |
|
|
150
|
+
|
|
151
|
+
### Extension model
|
|
152
|
+
|
|
153
|
+
Layer 2 is composed of **interpreters** — ordinary Python modules that
|
|
154
|
+
encode reusable framework/library knowledge:
|
|
155
|
+
|
|
156
|
+
- **Route interpreters**: recognize registration patterns, produce Route objects.
|
|
157
|
+
- **Input interpreters**: map code expressions to typed request-read observations.
|
|
158
|
+
- **Gate interpreters**: classify decorators, calls, conditionals as security gates.
|
|
159
|
+
- **Effect interpreters**: classify calls and writes as security-relevant effects.
|
|
160
|
+
- **State interpreters**: identify framework-specific context access patterns.
|
|
161
|
+
- **Flow interpreters**: define source/sink/propagator rules for data-flow tracing.
|
|
162
|
+
|
|
163
|
+
Users extend or replace any interpreter. A project using Flask-RESTful adds
|
|
164
|
+
an interpreter that recognizes `Resource` subclasses as route handlers. A
|
|
165
|
+
project with custom auth adds an interpreter that recognizes its
|
|
166
|
+
`@requires_permission` decorator as a gate. These extensions have full
|
|
167
|
+
parity with the built-in Flask interpreters — the built-ins are just
|
|
168
|
+
default interpreter modules, not privileged internal code.
|
|
169
|
+
|
|
170
|
+
### API shape
|
|
171
|
+
|
|
172
|
+
Layer 2 exposes a `WebApp` object built from a `CodeIndex` plus a set of
|
|
173
|
+
active interpreters:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
app = WebApp.from_index(idx, interpreters=flask_defaults())
|
|
177
|
+
|
|
178
|
+
app.routes # RouteCollection — framework-specific
|
|
179
|
+
app.request_reads # RequestReadCollection
|
|
180
|
+
app.gates # GateCollection
|
|
181
|
+
app.effects # EffectCollection
|
|
182
|
+
app.hooks # HookCollection
|
|
183
|
+
app.context_accesses # ContextAccessCollection
|
|
184
|
+
app.classified_mutations # ClassifiedMutationCollection
|
|
185
|
+
|
|
186
|
+
app.trace_flow(source, sink) # on-demand data-flow traversal
|
|
187
|
+
app.reachable_from(function) # transitive closure with framework edges
|
|
188
|
+
app.enhanced_call_graph # call graph with framework-injected edges
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Every object returned is frozen. Layer 3 cannot mutate Layer 2 data.
|
|
192
|
+
|
|
193
|
+
### Execution
|
|
194
|
+
|
|
195
|
+
Runs per detection invocation. Layer 2 code executes each time a rule runs,
|
|
196
|
+
so interpreter changes take effect immediately without re-running the
|
|
197
|
+
internal pipeline.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Layer 3: Rule API
|
|
202
|
+
|
|
203
|
+
### Responsibility
|
|
204
|
+
|
|
205
|
+
Provide rule authors with typed, composable, notebook-friendly tools for
|
|
206
|
+
navigating analyzed codebases, expressing security invariants, building
|
|
207
|
+
evidence chains, and producing vulnerability candidates.
|
|
208
|
+
|
|
209
|
+
### What it provides
|
|
210
|
+
|
|
211
|
+
- **Domain navigation**: `Route`, `Function`, `CodeScope` with fluent queries.
|
|
212
|
+
- **Scoped queries**: `.reads()`, `.effects()`, `.gates()`, `.calls()` within
|
|
213
|
+
a code scope (route body, reachable code, function body).
|
|
214
|
+
- **Control flow**: `.cfg.dominates()`, `.cfg.precedes()`, `.cfg.ordered()`.
|
|
215
|
+
- **Value flow**: `.value.flows_to()`, `.value_bindings.to()`.
|
|
216
|
+
- **Collections**: filtering, grouping, chaining over domain objects.
|
|
217
|
+
- **Evidence building**: `CandidateBuilder` with evidence, missing evidence,
|
|
218
|
+
analysis gaps, severity, tags.
|
|
219
|
+
- **Detector framework**: `@detector`, `@invariant`, `@for_routes`, config.
|
|
220
|
+
- **Dev tools**: `trace_detector()`, `dry_run()`, `explain()`.
|
|
221
|
+
|
|
222
|
+
### Consumers
|
|
223
|
+
|
|
224
|
+
- Security researchers writing detection rules.
|
|
225
|
+
- Notebook-driven interactive code exploration.
|
|
226
|
+
- Batch detection across a repository corpus.
|
|
227
|
+
- Hypothesis testing and rule prototyping.
|
|
228
|
+
|
|
229
|
+
Layer 3 consumers never import Layer 1 types, never read raw files, and
|
|
230
|
+
never need to understand static analysis internals.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Data Flow
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
Source files
|
|
238
|
+
│
|
|
239
|
+
▼
|
|
240
|
+
Layer 1: Semgrep extraction → normalization → AST passes → merge → index
|
|
241
|
+
│
|
|
242
|
+
│ Persisted artifacts: analysis-store/repos/<slug>/<snapshot>/
|
|
243
|
+
│ - raw/semgrep/ (call graph, symbols, svalues)
|
|
244
|
+
│ - normalized/ (entities, calls, cfgs, hierarchy, symbols,
|
|
245
|
+
│ value_flow, attributes, decorators)
|
|
246
|
+
│ - projections/ (merged_call_graph, indexes)
|
|
247
|
+
│ - manifest.json (version hashes, step status)
|
|
248
|
+
│ - errors.jsonl (extraction failures, gaps)
|
|
249
|
+
│
|
|
250
|
+
▼
|
|
251
|
+
Layer 2: Framework interpreters → domain construction → flow tracing
|
|
252
|
+
│
|
|
253
|
+
│ Runtime objects (not persisted by default):
|
|
254
|
+
│ - Route, RequestRead, Gate, Effect, Hook, ContextAccess
|
|
255
|
+
│ - Enhanced call graph (with framework-specific edges)
|
|
256
|
+
│ - Classified mutations, method branches
|
|
257
|
+
│ - On-demand flow traces
|
|
258
|
+
│
|
|
259
|
+
▼
|
|
260
|
+
Layer 3: Rule execution → candidate emission
|
|
261
|
+
│
|
|
262
|
+
│ Output: candidates.jsonl, reports, evidence packs
|
|
263
|
+
│
|
|
264
|
+
▼
|
|
265
|
+
Triage and reporting
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Execution Model
|
|
271
|
+
|
|
272
|
+
| Concern | When it runs | Persisted? | Invalidated by |
|
|
273
|
+
|---------|-------------|------------|----------------|
|
|
274
|
+
| Layer 1 extraction | Once per repo snapshot | Yes — artifact tree | Source change, tool version change |
|
|
275
|
+
| Layer 2 interpretation | Per detection run | No (optionally cached) | Interpreter change, Layer 1 change |
|
|
276
|
+
| Layer 3 detection | Per rule invocation | Candidates persisted | Rule change, config change, Layer 2 change |
|
|
277
|
+
|
|
278
|
+
Layer 1 is the expensive step. Layer 2 and Layer 3 are cheap and
|
|
279
|
+
re-run freely. This split means that adding support for a new
|
|
280
|
+
framework, fixing a gate recognition pattern, or adjusting effect
|
|
281
|
+
classification requires zero re-extraction.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Extension Points
|
|
286
|
+
|
|
287
|
+
| Extension | Layer | Mechanism | Requires re-extraction? |
|
|
288
|
+
|-----------|-------|-----------|------------------------|
|
|
289
|
+
| New route registration pattern | 2 | Route interpreter module | No |
|
|
290
|
+
| New request parser library | 2 | Input interpreter module | No |
|
|
291
|
+
| New auth decorator pattern | 2 | Gate interpreter module | No |
|
|
292
|
+
| New ORM write pattern | 2 | Effect interpreter module | No |
|
|
293
|
+
| New context proxy | 2 | State interpreter module | No |
|
|
294
|
+
| Custom flow source/sink | 2 | Flow interpreter module | No |
|
|
295
|
+
| New detection rule | 3 | Detector module | No |
|
|
296
|
+
| New model library | 3 | Ordinary Python module | No |
|
|
297
|
+
| New extraction pass | 1 | Fact builder module | Yes |
|
|
298
|
+
|
|
299
|
+
Extension through Layer 2 interpreters is the expected path. Layer 1
|
|
300
|
+
extraction changes only when the structural fact base is missing a
|
|
301
|
+
primitive observation that no interpreter can recover from existing
|
|
302
|
+
facts.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Dependency Rules
|
|
307
|
+
|
|
308
|
+
1. **Layer 3 depends only on Layer 2.** Rule code imports Layer 2's domain
|
|
309
|
+
types and API. It never imports Layer 1 types, never reads analysis
|
|
310
|
+
store files, never instantiates code index objects.
|
|
311
|
+
|
|
312
|
+
2. **Layer 2 depends only on Layer 1.** Interpreter code imports Layer 1's
|
|
313
|
+
`CodeIndex` API. It never reads raw Semgrep output, never parses JSONL
|
|
314
|
+
files, never accesses internal storage paths.
|
|
315
|
+
|
|
316
|
+
3. **Layer 1 depends on nothing above.** It has no knowledge of frameworks,
|
|
317
|
+
routes, security semantics, or vulnerability patterns.
|
|
318
|
+
|
|
319
|
+
4. **No skipping.** Layer 3 cannot reach into Layer 1 for "just this one
|
|
320
|
+
query." If Layer 3 needs something, Layer 2 must expose it. If
|
|
321
|
+
Layer 2 needs something, Layer 1 must expose it.
|
|
322
|
+
|
|
323
|
+
5. **Boundary immutability.** Objects crossing layer boundaries are frozen.
|
|
324
|
+
The receiving layer cannot modify what the producing layer tracks.
|
|
325
|
+
|
|
326
|
+
6. **Vocabulary matches the consumer.** Layer 1 speaks Python structural
|
|
327
|
+
vocabulary (functions, calls, CFG blocks). Layer 2 speaks web
|
|
328
|
+
application security vocabulary (routes, inputs, gates, effects).
|
|
329
|
+
Layer 3 speaks vulnerability research vocabulary (invariants,
|
|
330
|
+
confusion, candidates, evidence).
|