feat(analysis): taint propagation engine + source/sink/sanitizer catalog#72
Closed
smochan wants to merge 1 commit into
Closed
feat(analysis): taint propagation engine + source/sink/sanitizer catalog#72smochan wants to merge 1 commit into
smochan wants to merge 1 commit into
Conversation
Implements Capability A from docs/GAP_ANALYSIS_VS_LLM_REVIEWER.md (C3, PR C3). codegraph/analysis/taint_catalog.py: - SourceSpec / SinkSpec / SanitizerSpec dataclasses - Bundled default catalog: 7 sources (http_request, fetch_response, llm_output, file_read, scraped_dom, route_param), 14 sinks (network/sql/eval/exec/path/dom), 6 sanitizers (url-allowlist, html-escape, shell-quote, zod/pydantic, sql-escape) - os.environ explicitly excluded from sources (operator config, not user data) - load_taint_catalog(): searches .codegraph/taint.yml with merge/replace semantics codegraph/analysis/taint.py: - TaintFinding / TaintHop dataclasses with to_dict() for serialisation - propagate(graph, catalog, max_depth=6) -> list[TaintFinding] - Seed kinds: route-param (PARAMETER nodes of ROUTE-decorated handlers) + call-result (VARIABLE nodes assigned from matching unresolved::ret:: sentinels) - Forward propagation over DATA_ASSIGN + DATA_RETURN edges (node-to-node) - Call-through propagation: taint flows through unresolvable external calls to their return-value variables (enables shlex.quote class-mismatch detection) - Inter-procedural hop: DATA_ARG -> resolved callee PARAMETER node via CALLS edges or tail-qualname scan; confidence x0.8 for indirect hops - Sanitizer absorption: cleared_classes frozenset tracks per-path cleared sinks; at sink time, suppressed when sink class is covered - Visited-set on (node_id, cleared_classes) for cycle/termination safety - Depth cap (default 6) mirrors DF4 max_depth tests/test_taint.py: 27 tests covering all 9 required spec cases plus unit tests for catalog validation, YAML loading, to_dict, and edge cases. Performance: propagate() on codegraph's own 14K-node graph completes in 25ms (well under the 5s gate). Finding count: 0 (expected — codegraph has no route-decorated handlers matching the default catalog patterns).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Track C3, stacked on #68 — the Phase-4 flagship from docs/GAP_ANALYSIS_VS_LLM_REVIEWER.md. codegraph now tracks untrusted values from sources to dangerous sinks with witness paths.
analysis/taint_catalog.py: YAML catalog (.codegraph/taint.yml, extend-by-default /replace: true) of sources (route params, request.*, fetch responses, LLM output), sinks (network/sql/eval/exec/dom/path with per-class severity), sanitizers (clear specific sink classes)analysis/taint.py: worklist propagation over C1's DATA_* edges; route-param seeding via DF1 ROUTE edges; call-through bridging (arg → retsentinels, ×0.9 confidence); sanitizer absorption tracked as cleared-class sets in visited state(node, frozenset(cleared))— re-visits allowed on different sanitizer histories, termination guaranteed; depth cap 6Adversarial e2e validation by reviewer (full build pipeline on a deliberately vulnerable FastAPI app):
target_urlparam →requests.get→ high, confidence 1.0 ✓cmdparam →expanded = cmd + …→subprocess.run→ critical, witness path includes the intermediate assignment ✓Test plan
🤖 Generated with Claude Code