@clear-capabilities/agentic-security-scanner 0.84.1 → 0.118.2
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.
- package/CHANGELOG.md +404 -0
- package/dist/178.index.js +1 -1
- package/dist/384.index.js +1 -1
- package/dist/637.index.js +1 -1
- package/dist/838.index.js +1 -1
- package/dist/agentic-security.mjs +84 -84
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +12 -6
- package/src/.agentic-security/dpia.md +26 -0
- package/src/.agentic-security/pqc-migration-plan.json +80 -0
- package/src/.agentic-security/pqc-migration-plan.md +32 -0
- package/src/.agentic-security/sbom-history/0775d96ba4cf814520d02760cfb3010760c7684f.json +6 -0
- package/src/.agentic-security/sbom-history/29300441d3460832137a8e51a92b74068cad2f15.json +6 -0
- package/src/.agentic-security/sbom-history/3852ad2aa0e50951bed0c930c29d1861aa13d048.json +6 -0
- package/src/.agentic-security/sbom-history/3d96e2daec97e3226c9679bac6e64a89ca10bfe9.json +6 -0
- package/src/.agentic-security/sbom-history/5f0b136622fce09b469a1a6137c04d5b18652ea4.json +6 -0
- package/src/.agentic-security/sbom-history/64e30595d447b62344d0d9200760269df2095332.json +6 -0
- package/src/.agentic-security/sbom-history/71f3241902c9e7437764e3caa046ba8a3bcdd32a.json +6 -0
- package/src/.agentic-security/sbom-history/99c372cdc33ecc9dde92960b4ffadf7775860e61.json +6 -0
- package/src/.agentic-security/sbom-history/9c93b15e8cf3ff2ddb8cdae92371b82e178b463c.json +6 -0
- package/src/.agentic-security/sbom-history/a3544abf1863d71776b61302ca74d9ead2b26a9f.json +6 -0
- package/src/.agentic-security/sbom-history/dca15abdec43c508aa342db86dc5db8d7f01fbbe.json +6 -0
- package/src/.agentic-security/threat-model.json +3702 -0
- package/src/.agentic-security/threat-model.md +118 -0
- package/src/dataflow/.agentic-security/dpia.md +26 -0
- package/src/dataflow/.agentic-security/sbom-history/15d7c4d20f9d968ebec29445c9e9b3fc6f74e6a1.json +6 -0
- package/src/dataflow/.agentic-security/sbom-history/3852ad2aa0e50951bed0c930c29d1861aa13d048.json +6 -0
- package/src/dataflow/.agentic-security/sbom-history/73166872888d9ddcbe98645af818ecc7d8917b07.json +6 -0
- package/src/dataflow/.agentic-security/sbom-history/8869fe64035bec0152d92ece961e9369d8637076.json +6 -0
- package/src/dataflow/.agentic-security/sbom-history/9c93b15e8cf3ff2ddb8cdae92371b82e178b463c.json +6 -0
- package/src/dataflow/.agentic-security/sbom-history/b7ac2dada4a9216ccfe8969fc57f988c83f46975.json +6 -0
- package/src/dataflow/.agentic-security/threat-model.json +161 -0
- package/src/dataflow/.agentic-security/threat-model.md +43 -0
- package/src/dataflow/CLAUDE.md +17 -5
- package/src/dataflow/catalog.js +9 -0
- package/src/dataflow/engine.js +30 -4
- package/src/dataflow/index.js +8 -0
- package/src/dataflow/proof-gate.js +95 -0
- package/src/dataflow/summaries.js +44 -5
- package/src/engine.js +199 -5
- package/src/ir/.agentic-security/dpia.md +26 -0
- package/src/ir/.agentic-security/exploit-bundles.json +77 -0
- package/src/ir/.agentic-security/sbom-history/73166872888d9ddcbe98645af818ecc7d8917b07.json +6 -0
- package/src/ir/.agentic-security/sbom-history/b5f468a158f6a145aedd8680841c106b9809f16b.json +6 -0
- package/src/ir/.agentic-security/threat-model.json +143 -0
- package/src/ir/.agentic-security/threat-model.md +39 -0
- package/src/ir/CLAUDE.md +1 -0
- package/src/ir/callgraph.js +12 -1
- package/src/ir/tree-sitter-loader.js +108 -0
- package/src/posture/.agentic-security/dpia.md +26 -0
- package/src/posture/.agentic-security/pqc-migration-plan.json +65 -0
- package/src/posture/.agentic-security/pqc-migration-plan.md +30 -0
- package/src/posture/.agentic-security/sbom-history/0724c133d2943c87555695b5b2adcfcfc3373a2d.json +6 -0
- package/src/posture/.agentic-security/sbom-history/7d45b5e03804aac084b4a2b4dc8c6f10107d2005.json +6 -0
- package/src/posture/.agentic-security/sbom-history/99c372cdc33ecc9dde92960b4ffadf7775860e61.json +6 -0
- package/src/posture/.agentic-security/sbom-history/b7ac2dada4a9216ccfe8969fc57f988c83f46975.json +6 -0
- package/src/posture/.agentic-security/threat-model.json +2038 -0
- package/src/posture/.agentic-security/threat-model.md +73 -0
- package/src/posture/auditor-walkthrough.js +1 -1
- package/src/posture/corpus-status.js +74 -0
- package/src/posture/coverage-report.js +113 -0
- package/src/posture/holdout-eval.js +57 -0
- package/src/posture/pr-augment.js +1 -1
- package/src/posture/router.js +37 -7
- package/src/report/.agentic-security/dpia.md +26 -0
- package/src/report/.agentic-security/sbom-history/7d45b5e03804aac084b4a2b4dc8c6f10107d2005.json +6 -0
- package/src/report/.agentic-security/sbom-history/f94be839aa6a1011f53da016416a561698b8f338.json +6 -0
- package/src/report/.agentic-security/threat-model.json +7 -0
- package/src/report/.agentic-security/threat-model.md +22 -0
- package/src/report/index.js +18 -1
- package/src/sast/.agentic-security/dpia.md +26 -0
- package/src/sast/.agentic-security/pqc-migration-plan.json +65 -0
- package/src/sast/.agentic-security/pqc-migration-plan.md +30 -0
- package/src/sast/.agentic-security/sbom-history/043a7b401c68f5a298c83d4c42e94f118ff2a89a.json +6 -0
- package/src/sast/.agentic-security/sbom-history/0775d96ba4cf814520d02760cfb3010760c7684f.json +6 -0
- package/src/sast/.agentic-security/sbom-history/20d77ad7363a82777d506dedbbb1ecfed52f094a.json +6 -0
- package/src/sast/.agentic-security/sbom-history/29300441d3460832137a8e51a92b74068cad2f15.json +6 -0
- package/src/sast/.agentic-security/sbom-history/3852ad2aa0e50951bed0c930c29d1861aa13d048.json +6 -0
- package/src/sast/.agentic-security/sbom-history/3c6b3205f04e26f7654943d465281d00e0fa395e.json +6 -0
- package/src/sast/.agentic-security/sbom-history/3d96e2daec97e3226c9679bac6e64a89ca10bfe9.json +6 -0
- package/src/sast/.agentic-security/sbom-history/5282502e090013219eb006f7e02d8c983bc29c8e.json +6 -0
- package/src/sast/.agentic-security/sbom-history/5f0b136622fce09b469a1a6137c04d5b18652ea4.json +6 -0
- package/src/sast/.agentic-security/sbom-history/64e30595d447b62344d0d9200760269df2095332.json +6 -0
- package/src/sast/.agentic-security/sbom-history/71f3241902c9e7437764e3caa046ba8a3bcdd32a.json +6 -0
- package/src/sast/.agentic-security/sbom-history/73514b485d4770f3c5ee57d87338bccd1c61d8b7.json +6 -0
- package/src/sast/.agentic-security/sbom-history/96fa584fc3134512237d58aac63d6f3778b0cbcb.json +6 -0
- package/src/sast/.agentic-security/sbom-history/99c372cdc33ecc9dde92960b4ffadf7775860e61.json +6 -0
- package/src/sast/.agentic-security/sbom-history/a3544abf1863d71776b61302ca74d9ead2b26a9f.json +6 -0
- package/src/sast/.agentic-security/sbom-history/a4a34ab8b3d758de2adc8c3dc3e42d4cb0db00a3.json +6 -0
- package/src/sast/.agentic-security/sbom-history/ac236ec3602cfc8fb133f389ec3687e409084673.json +6 -0
- package/src/sast/.agentic-security/sbom-history/b57b3e1292f1f9f0de6c5a34a436e330c78008a3.json +6 -0
- package/src/sast/.agentic-security/sbom-history/dca15abdec43c508aa342db86dc5db8d7f01fbbe.json +6 -0
- package/src/sast/.agentic-security/sbom-history/dcbfd4935922dd165093c08a1003c338eed937c5.json +6 -0
- package/src/sast/.agentic-security/sbom-history/fa017f725615b0293814344c8ef7dfeb06775ca0.json +6 -0
- package/src/sast/.agentic-security/threat-model.json +816 -0
- package/src/sast/.agentic-security/threat-model.md +91 -0
- package/src/sast/CLAUDE.md +9 -3
- package/src/sast/code-injection-multilang.js +117 -0
- package/src/sast/crypto-protocol.js +43 -1
- package/src/sast/csharp-structural.js +65 -0
- package/src/sast/csharp.js +3 -0
- package/src/sast/csrf.js +24 -3
- package/src/sast/csv-injection.js +84 -0
- package/src/sast/frontend-hygiene.js +106 -0
- package/src/sast/go-structural.js +60 -0
- package/src/sast/java-structural.js +81 -0
- package/src/sast/js-framework-structural.js +115 -0
- package/src/sast/kotlin.js +72 -0
- package/src/sast/ldap-injection.js +73 -17
- package/src/sast/open-redirect.js +47 -5
- package/src/sast/php.js +35 -0
- package/src/sast/python-structural.js +83 -0
- package/src/sast/redos-nfa.js +75 -0
- package/src/sast/response-splitting.js +48 -19
- package/src/sast/ruby.js +38 -0
- package/src/sast/secret-concat.js +60 -0
- package/src/sast/ssrf-cloud-metadata.js +13 -0
- package/src/sast/stored-taint.js +88 -0
- package/src/sast/tree-sitter-sinks.js +62 -0
- package/src/sast/weak-password-hash.js +28 -0
- package/src/sast/weak-randomness.js +46 -5
- package/src/sast/wrong-context-sanitizer.js +94 -0
- package/src/sast/xpath-injection.js +30 -6
- package/src/sast/xss-reflected-multilang.js +116 -0
- package/src/sast/xxe.js +67 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Threat Model (auto-generated)
|
|
2
|
+
|
|
3
|
+
Generated by agentic-security on 2026-06-01.
|
|
4
|
+
|
|
5
|
+
This threat model is derived from static analysis of the current codebase and is regenerated on every scan. It is intended as a working artifact, not a finished compliance document.
|
|
6
|
+
|
|
7
|
+
## Entities + boundaries
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
flowchart TB
|
|
11
|
+
subgraph External
|
|
12
|
+
route_GET__api_endpoint["http-route: GET /api/endpoint"]
|
|
13
|
+
route_GET__api_users_2["http-route: GET /api/users/2"]
|
|
14
|
+
route_GET__api_admin_users["http-route: GET /api/admin/users"]
|
|
15
|
+
route_GET__api_health["http-route: GET /api/health"]
|
|
16
|
+
route_GET___________________________________________________["http-route: GET
|
|
17
|
+
parser: "]
|
|
18
|
+
queue_sast_sensitive_data_logging_js_67["queue-consumer: sast/sensitive-data-logging.js:67"]
|
|
19
|
+
end
|
|
20
|
+
subgraph Application
|
|
21
|
+
end
|
|
22
|
+
External --> route_GET__api_endpoint
|
|
23
|
+
External --> route_GET__api_users_2
|
|
24
|
+
External --> route_GET__api_admin_users
|
|
25
|
+
External --> route_GET__api_health
|
|
26
|
+
External --> route_GET___________________________________________________
|
|
27
|
+
External --> queue_sast_sensitive_data_logging_js_67
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Assets
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## STRIDE threats
|
|
34
|
+
|
|
35
|
+
### Information Disclosure (27)
|
|
36
|
+
|
|
37
|
+
- [medium] **ssrf** (CWE-918) at `poc-video.js:98` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
38
|
+
- [low] **ssrf** (CWE-918) at `posture/attack-playbooks.js:72` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
39
|
+
- [low] **crypto-weak-cipher** (CWE-327) at `sast/crypto-protocol.js:141` — Weak symmetric cipher in use (DES / 3DES / RC4 / Blowfish / NULL / EXPORT)
|
|
40
|
+
- [low] **crypto-weak-cipher** (CWE-327) at `sast/crypto-protocol.js:143` — Weak symmetric cipher in use (DES / 3DES / RC4 / Blowfish / NULL / EXPORT)
|
|
41
|
+
- [low] **crypto-weak-cipher** (CWE-327) at `sast/crypto-protocol.js:145` — Weak symmetric cipher in use (DES / 3DES / RC4 / Blowfish / NULL / EXPORT)
|
|
42
|
+
- [low] **crypto-weak-cipher** (CWE-327) at `sast/crypto-protocol.js:149` — Weak symmetric cipher in use (DES / 3DES / RC4 / Blowfish / NULL / EXPORT)
|
|
43
|
+
- [low] **pqc-migration** (CWE-327) at `sast/post-quantum-crypto.js:136` — Pre-quantum RSA (rsa-encrypt) — replace with ML-KEM-768 before CRQC arrives
|
|
44
|
+
- [low] **zip-slip** (CWE-22) at `sast/zip-slip.js:192` — Zip Slip: archive entry.path written to filesystem without sanitization
|
|
45
|
+
- [low] **ssrf** (CWE-918) at `pr-comment.js:41` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
46
|
+
- [low] **ssrf** (CWE-918) at `dataflow/catalog.js:547` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
47
|
+
- [low] **ssrf** (CWE-918) at `dataflow/exploit-prover.js:33` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
48
|
+
- [low] **crypto-weak-hash** (CWE-327) at `ir/parser-py.helper.py:68` — Weak hash algorithm (MD5 / SHA-1 / MD2 / MD4) used
|
|
49
|
+
- [low] **ssrf** (CWE-918) at `posture/defender-agent.js:41` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
50
|
+
- [low] **ssrf** (CWE-918) at `posture/flow-narration.js:24` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
51
|
+
- [low] **pqc-migration** (CWE-327) at `posture/rule-pack-signing.js:187` — Pre-quantum ED25519 (ed25519) — replace with ML-DSA-65 before CRQC arrives
|
|
52
|
+
- [low] **ssrf** (CWE-918) at `posture/verifier.js:55` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
53
|
+
- [low] **ssrf** (CWE-918) at `sast/csharp-structural.js:60` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
54
|
+
- [low] **ssrf** (CWE-918) at `sast/go-extended.js:39` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
55
|
+
- [low] **ssrf** (CWE-918) at `sast/java-structural.js:76` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
56
|
+
- [low] **ssrf** (CWE-918) at `sast/js-framework-structural.js:69` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
57
|
+
- [low] **ssrf** (CWE-918) at `sast/kotlin.js:136` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
58
|
+
- [low] **ssrf** (CWE-918) at `sast/php.js:111` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
59
|
+
- [low] **ssrf** (CWE-918) at `sast/python-sinks.js:186` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
60
|
+
- [low] **ssrf** (CWE-918) at `sast/ssrf-cloud-metadata.js:61` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
61
|
+
- [low] **ssrf** (CWE-918) at `sast/ssrf-cloud-metadata.js:86` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
62
|
+
- … and 2 more
|
|
63
|
+
|
|
64
|
+
### Elevation of Privilege (22)
|
|
65
|
+
|
|
66
|
+
- [medium] **ssrf** (CWE-918) at `poc-video.js:98` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
67
|
+
- [low] **ssrf** (CWE-918) at `posture/attack-playbooks.js:72` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
68
|
+
- [low] **unsafe-deserialization-user-controlled-j** (CWE-502) at `sca/sigstore-verify.js:undefined` — Unsafe Deserialization (User-Controlled JSON)
|
|
69
|
+
- [low] **prototype-pollution** (CWE-1321) at `posture/adversarial-self-test.js:60` — Prototype Pollution: Direct write to __proto__ / constructor.prototype
|
|
70
|
+
- [low] **llm-app-security** (CWE-502) at `sast/llm-app.js:163` — Untrusted Model Load — model file loaded from a non-literal path
|
|
71
|
+
- [low] **llm-app-security** (CWE-502) at `sast/model-load.js:45` — Untrusted Model Load — model file loaded from a non-literal path
|
|
72
|
+
- [low] **ssrf** (CWE-918) at `pr-comment.js:41` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
73
|
+
- [low] **ssrf** (CWE-918) at `dataflow/catalog.js:547` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
74
|
+
- [low] **ssrf** (CWE-918) at `dataflow/exploit-prover.js:33` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
75
|
+
- [low] **ssrf** (CWE-918) at `posture/defender-agent.js:41` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
76
|
+
- [low] **ssrf** (CWE-918) at `posture/flow-narration.js:24` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
77
|
+
- [low] **ssrf** (CWE-918) at `posture/verifier.js:55` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
78
|
+
- [low] **ssrf** (CWE-918) at `sast/csharp-structural.js:60` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
79
|
+
- [low] **ssrf** (CWE-918) at `sast/go-extended.js:39` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
80
|
+
- [low] **ssrf** (CWE-918) at `sast/java-structural.js:76` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
81
|
+
- [low] **ssrf** (CWE-918) at `sast/js-framework-structural.js:69` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
82
|
+
- [low] **ssrf** (CWE-918) at `sast/kotlin.js:136` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
83
|
+
- [low] **ssrf** (CWE-918) at `sast/php.js:111` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
84
|
+
- [low] **ssrf** (CWE-918) at `sast/python-sinks.js:186` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
85
|
+
- [low] **ssrf** (CWE-918) at `sast/ssrf-cloud-metadata.js:61` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
86
|
+
- [low] **ssrf** (CWE-918) at `sast/ssrf-cloud-metadata.js:86` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
87
|
+
- [low] **ssrf** (CWE-918) at `sast/ssrf-cloud-metadata.js:15` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
88
|
+
|
|
89
|
+
### Tampering (236)
|
|
90
|
+
|
|
91
|
+
- [medium] **dos-sync-io** (CWE-400) at `posture/deploy-platform.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
92
|
+
- [low] **mass-assignment** (CWE-915) at `ir/parser-cs.js:undefined` — Mass Assignment (req.body Direct to Model)
|
|
93
|
+
- [low] **mass-assignment** (CWE-915) at `ir/parser-go.js:undefined` — Mass Assignment (req.body Direct to Model)
|
|
94
|
+
- [low] **mass-assignment** (CWE-915) at `ir/parser-kt.js:undefined` — Mass Assignment (req.body Direct to Model)
|
|
95
|
+
- [low] **mass-assignment** (CWE-915) at `ir/parser-php.js:undefined` — Mass Assignment (req.body Direct to Model)
|
|
96
|
+
- [low] **mass-assignment** (CWE-915) at `ir/parser-rb.js:undefined` — Mass Assignment (req.body Direct to Model)
|
|
97
|
+
- [low] **mass-assignment** (CWE-915) at `posture/integrity.js:undefined` — Mass Assignment (req.body Direct to Model)
|
|
98
|
+
- [low] **dos-sync-io** (CWE-400) at `badge.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
99
|
+
- [low] **dos-sync-io** (CWE-400) at `history-scan.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
100
|
+
- [low] **dos-sync-io** (CWE-400) at `leaderboard.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
101
|
+
- [low] **dos-sync-io** (CWE-400) at `dataflow/cross-service-taint.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
102
|
+
- [low] **dos-sync-io** (CWE-400) at `dataflow/ifds-precise.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
103
|
+
- [low] **dos-sync-io** (CWE-400) at `dataflow/incremental.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
104
|
+
- [low] **dos-sync-io** (CWE-400) at `integrations/index.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
105
|
+
- [low] **dos-sync-io** (CWE-400) at `integrations/tickets.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
106
|
+
- [low] **dos-sync-io** (CWE-400) at `ir/cpp-preprocessor.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
107
|
+
- [low] **dos-sync-io** (CWE-400) at `ir/type-stubs.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
108
|
+
- [low] **dos-sync-io** (CWE-400) at `llm-validator/consistency.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
109
|
+
- [low] **dos-sync-io** (CWE-400) at `llm-validator/index.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
110
|
+
- [low] **dos-sync-io** (CWE-400) at `mcp/audit.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
111
|
+
- [low] **dos-sync-io** (CWE-400) at `mcp/server.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
112
|
+
- [low] **dos-sync-io** (CWE-400) at `mcp/tools.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
113
|
+
- [low] **dos-sync-io** (CWE-400) at `posture/agents-memory.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
114
|
+
- [low] **dos-sync-io** (CWE-400) at `posture/api-contract.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
115
|
+
- [low] **dos-sync-io** (CWE-400) at `posture/auditor-walkthrough.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
116
|
+
- … and 211 more
|
|
117
|
+
|
|
118
|
+
## Attack trees
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Data Protection Impact Assessment (DPIA)
|
|
2
|
+
|
|
3
|
+
Generated by agentic-security scanner on 2026-05-31.
|
|
4
|
+
|
|
5
|
+
This is an automated DPIA scaffold derived from static analysis.
|
|
6
|
+
It must be reviewed and completed by a privacy officer before use.
|
|
7
|
+
|
|
8
|
+
## Data classes identified
|
|
9
|
+
|
|
10
|
+
## Privacy-related findings
|
|
11
|
+
|
|
12
|
+
| Severity | File:Line | Class → Sink | Description |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
|
|
15
|
+
## Regulatory framework mapping
|
|
16
|
+
|
|
17
|
+
- **GDPR Art. 35** — DPIA required when processing is likely to result in high risk to data subjects.
|
|
18
|
+
- **CCPA §1798.130** — Notice + access rights for collected personal information.
|
|
19
|
+
|
|
20
|
+
## Reviewer checklist
|
|
21
|
+
|
|
22
|
+
- [ ] Confirm each PII field's collection has a documented lawful basis
|
|
23
|
+
- [ ] Confirm retention period for each class is documented
|
|
24
|
+
- [ ] Confirm DSAR (data subject access request) workflow exists
|
|
25
|
+
- [ ] Confirm encryption at rest + in transit for each class
|
|
26
|
+
- [ ] Confirm logging of PII access for audit (where applicable)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
{
|
|
2
|
+
"entities": [],
|
|
3
|
+
"boundaries": [],
|
|
4
|
+
"assets": [],
|
|
5
|
+
"threats": [
|
|
6
|
+
{
|
|
7
|
+
"stride": "T",
|
|
8
|
+
"strideLabel": "Tampering",
|
|
9
|
+
"cwe": "CWE-400",
|
|
10
|
+
"family": "dos-sync-io",
|
|
11
|
+
"severity": "medium",
|
|
12
|
+
"file": "cross-service-taint.js",
|
|
13
|
+
"vuln": "Synchronous Blocking I/O (DoS Risk in Server Context)",
|
|
14
|
+
"finding_id": "struct:cross-service-taint.js:53:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
|
|
15
|
+
"affectsAsset": null,
|
|
16
|
+
"atEntity": null
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"stride": "T",
|
|
20
|
+
"strideLabel": "Tampering",
|
|
21
|
+
"cwe": "CWE-400",
|
|
22
|
+
"family": "dos-sync-io",
|
|
23
|
+
"severity": "medium",
|
|
24
|
+
"file": "ifds-precise.js",
|
|
25
|
+
"vuln": "Synchronous Blocking I/O (DoS Risk in Server Context)",
|
|
26
|
+
"finding_id": "struct:ifds-precise.js:177:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
|
|
27
|
+
"affectsAsset": null,
|
|
28
|
+
"atEntity": null
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"stride": "T",
|
|
32
|
+
"strideLabel": "Tampering",
|
|
33
|
+
"cwe": "CWE-400",
|
|
34
|
+
"family": "dos-sync-io",
|
|
35
|
+
"severity": "medium",
|
|
36
|
+
"file": "incremental.js",
|
|
37
|
+
"vuln": "Synchronous Blocking I/O (DoS Risk in Server Context)",
|
|
38
|
+
"finding_id": "struct:incremental.js:50:Synchronous_Blocking_I/O_(DoS_Risk_in_Server_Context)",
|
|
39
|
+
"affectsAsset": null,
|
|
40
|
+
"atEntity": null
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"stride": "I",
|
|
44
|
+
"strideLabel": "Information Disclosure",
|
|
45
|
+
"cwe": "CWE-918",
|
|
46
|
+
"family": "ssrf",
|
|
47
|
+
"severity": "medium",
|
|
48
|
+
"file": "catalog.js",
|
|
49
|
+
"line": 547,
|
|
50
|
+
"vuln": "SSRF: explicit reference to cloud instance-metadata endpoint",
|
|
51
|
+
"finding_id": "ssrf-meta-hardcoded:catalog.js:547",
|
|
52
|
+
"affectsAsset": null,
|
|
53
|
+
"atEntity": null
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"stride": "E",
|
|
57
|
+
"strideLabel": "Elevation of Privilege",
|
|
58
|
+
"cwe": "CWE-918",
|
|
59
|
+
"family": "ssrf",
|
|
60
|
+
"severity": "medium",
|
|
61
|
+
"file": "catalog.js",
|
|
62
|
+
"line": 547,
|
|
63
|
+
"vuln": "SSRF: explicit reference to cloud instance-metadata endpoint",
|
|
64
|
+
"finding_id": "ssrf-meta-hardcoded:catalog.js:547",
|
|
65
|
+
"affectsAsset": null,
|
|
66
|
+
"atEntity": null
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"stride": "T",
|
|
70
|
+
"strideLabel": "Tampering",
|
|
71
|
+
"cwe": "CWE-367",
|
|
72
|
+
"family": "toctou-file-existence-permission-check-b",
|
|
73
|
+
"severity": "medium",
|
|
74
|
+
"file": "cross-service-taint.js",
|
|
75
|
+
"line": 53,
|
|
76
|
+
"vuln": "TOCTOU: file existence/permission check before open",
|
|
77
|
+
"finding_id": "toctou-fs:cross-service-taint.js:53",
|
|
78
|
+
"affectsAsset": null,
|
|
79
|
+
"atEntity": null
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"stride": "T",
|
|
83
|
+
"strideLabel": "Tampering",
|
|
84
|
+
"cwe": "CWE-367",
|
|
85
|
+
"family": "toctou-file-existence-permission-check-b",
|
|
86
|
+
"severity": "medium",
|
|
87
|
+
"file": "cross-service-taint.js",
|
|
88
|
+
"line": 97,
|
|
89
|
+
"vuln": "TOCTOU: file existence/permission check before open",
|
|
90
|
+
"finding_id": "toctou-fs:cross-service-taint.js:97",
|
|
91
|
+
"affectsAsset": null,
|
|
92
|
+
"atEntity": null
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"stride": "I",
|
|
96
|
+
"strideLabel": "Information Disclosure",
|
|
97
|
+
"cwe": "CWE-918",
|
|
98
|
+
"family": "ssrf",
|
|
99
|
+
"severity": "medium",
|
|
100
|
+
"file": "exploit-prover.js",
|
|
101
|
+
"line": 33,
|
|
102
|
+
"vuln": "SSRF: explicit reference to cloud instance-metadata endpoint",
|
|
103
|
+
"finding_id": "ssrf-meta-hardcoded:exploit-prover.js:33",
|
|
104
|
+
"affectsAsset": null,
|
|
105
|
+
"atEntity": null
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"stride": "E",
|
|
109
|
+
"strideLabel": "Elevation of Privilege",
|
|
110
|
+
"cwe": "CWE-918",
|
|
111
|
+
"family": "ssrf",
|
|
112
|
+
"severity": "medium",
|
|
113
|
+
"file": "exploit-prover.js",
|
|
114
|
+
"line": 33,
|
|
115
|
+
"vuln": "SSRF: explicit reference to cloud instance-metadata endpoint",
|
|
116
|
+
"finding_id": "ssrf-meta-hardcoded:exploit-prover.js:33",
|
|
117
|
+
"affectsAsset": null,
|
|
118
|
+
"atEntity": null
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"stride": "T",
|
|
122
|
+
"strideLabel": "Tampering",
|
|
123
|
+
"cwe": "CWE-367",
|
|
124
|
+
"family": "toctou-file-existence-permission-check-b",
|
|
125
|
+
"severity": "medium",
|
|
126
|
+
"file": "ifds-precise.js",
|
|
127
|
+
"line": 177,
|
|
128
|
+
"vuln": "TOCTOU: file existence/permission check before open",
|
|
129
|
+
"finding_id": "toctou-fs:ifds-precise.js:177",
|
|
130
|
+
"affectsAsset": null,
|
|
131
|
+
"atEntity": null
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"stride": "T",
|
|
135
|
+
"strideLabel": "Tampering",
|
|
136
|
+
"cwe": "CWE-367",
|
|
137
|
+
"family": "toctou-file-existence-permission-check-b",
|
|
138
|
+
"severity": "medium",
|
|
139
|
+
"file": "incremental.js",
|
|
140
|
+
"line": 50,
|
|
141
|
+
"vuln": "TOCTOU: file existence/permission check before open",
|
|
142
|
+
"finding_id": "toctou-fs:incremental.js:50",
|
|
143
|
+
"affectsAsset": null,
|
|
144
|
+
"atEntity": null
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"stride": "T",
|
|
148
|
+
"strideLabel": "Tampering",
|
|
149
|
+
"cwe": "CWE-367",
|
|
150
|
+
"family": "toctou-file-existence-permission-check-b",
|
|
151
|
+
"severity": "medium",
|
|
152
|
+
"file": "incremental.js",
|
|
153
|
+
"line": 68,
|
|
154
|
+
"vuln": "TOCTOU: file existence/permission check before open",
|
|
155
|
+
"finding_id": "toctou-fs:incremental.js:68",
|
|
156
|
+
"affectsAsset": null,
|
|
157
|
+
"atEntity": null
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"attackTrees": []
|
|
161
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Threat Model (auto-generated)
|
|
2
|
+
|
|
3
|
+
Generated by agentic-security on 2026-05-31.
|
|
4
|
+
|
|
5
|
+
This threat model is derived from static analysis of the current codebase and is regenerated on every scan. It is intended as a working artifact, not a finished compliance document.
|
|
6
|
+
|
|
7
|
+
## Entities + boundaries
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
flowchart TB
|
|
11
|
+
subgraph External
|
|
12
|
+
end
|
|
13
|
+
subgraph Application
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Assets
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## STRIDE threats
|
|
21
|
+
|
|
22
|
+
### Tampering (8)
|
|
23
|
+
|
|
24
|
+
- [medium] **dos-sync-io** (CWE-400) at `cross-service-taint.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
25
|
+
- [medium] **dos-sync-io** (CWE-400) at `ifds-precise.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
26
|
+
- [medium] **dos-sync-io** (CWE-400) at `incremental.js:undefined` — Synchronous Blocking I/O (DoS Risk in Server Context)
|
|
27
|
+
- [medium] **toctou-file-existence-permission-check-b** (CWE-367) at `cross-service-taint.js:53` — TOCTOU: file existence/permission check before open
|
|
28
|
+
- [medium] **toctou-file-existence-permission-check-b** (CWE-367) at `cross-service-taint.js:97` — TOCTOU: file existence/permission check before open
|
|
29
|
+
- [medium] **toctou-file-existence-permission-check-b** (CWE-367) at `ifds-precise.js:177` — TOCTOU: file existence/permission check before open
|
|
30
|
+
- [medium] **toctou-file-existence-permission-check-b** (CWE-367) at `incremental.js:50` — TOCTOU: file existence/permission check before open
|
|
31
|
+
- [medium] **toctou-file-existence-permission-check-b** (CWE-367) at `incremental.js:68` — TOCTOU: file existence/permission check before open
|
|
32
|
+
|
|
33
|
+
### Information Disclosure (2)
|
|
34
|
+
|
|
35
|
+
- [medium] **ssrf** (CWE-918) at `catalog.js:547` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
36
|
+
- [medium] **ssrf** (CWE-918) at `exploit-prover.js:33` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
37
|
+
|
|
38
|
+
### Elevation of Privilege (2)
|
|
39
|
+
|
|
40
|
+
- [medium] **ssrf** (CWE-918) at `catalog.js:547` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
41
|
+
- [medium] **ssrf** (CWE-918) at `exploit-prover.js:33` — SSRF: explicit reference to cloud instance-metadata endpoint
|
|
42
|
+
|
|
43
|
+
## Attack trees
|
package/src/dataflow/CLAUDE.md
CHANGED
|
@@ -5,23 +5,34 @@ Layer-2 taint engine. Walks the Layer-1 IR (`../ir/`) with field-sensitive forwa
|
|
|
5
5
|
## Scope — what we actually model
|
|
6
6
|
|
|
7
7
|
- **Intra-procedural field-sensitive taint** with access-path lattice (`access-paths.js`). `user.email` is distinguishable from `user.password`.
|
|
8
|
-
- **
|
|
8
|
+
- **Value-context-sensitive interprocedural taint (FR-SEM-2).** `SummaryCache` (`summaries.js`) holds a distinct summary per distinct entry-taint-state. A pre-pass computes the empty-entry base for every function; call sites then lazily compute the summary under their actual tainted-arg context (at both assign-from-call and plain-call sites) so a helper that is clean with clean args but tainted with user input is detected per call site. Bounded by a per-function context cap (`AGENTIC_SECURITY_KCFA_MAX_CONTEXTS`, default 16; 0 = monovariant). Over the cap → reuse the empty-entry summary.
|
|
9
9
|
- **Catalog-driven source/sink/sanitizer matching.** Add entries in `catalog.js`. Each entry: `kind` ∈ {source, sink, sanitizer}, plus language + framework + match shape. 200+ entries spanning Express/Flask/FastAPI/Django/Rails/PHP/Go-net-http/Gin/Echo.
|
|
10
10
|
- **Path feasibility.** Constant-folds `if` conditions to prune unreachable branches.
|
|
11
11
|
- **Per-flow source attribution.** Sources reported on a finding are the ones actually reaching the sink argument (via free-var matching in the sink expression), NOT the first source the worklist happened to see. Premortem-derived.
|
|
12
12
|
|
|
13
|
-
## Scope —
|
|
13
|
+
## Scope — now modelled (was previously listed as gaps; closed in v0.66)
|
|
14
14
|
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
15
|
+
- **Mutated-parameter taint at call sites.** `engine.js` consults `SummaryCache.applyAtCallSite` at both assign-from-call and plain-call sites: a callee that mutates a param (e.g. `Object.assign(target, tainted)`, `_.merge`) taints the caller's argument variable. Covered by `test/interproc-k2.test.js`.
|
|
16
|
+
- **Higher-order taint flow.** `_higherOrderInvocations` recorded during `analyzeFunction` are consumed in `runTaintEngine`: the callback is resolved, analyzed with a tainted parameter, and its findings merged back into the caller (`_via: 'higher-order'`, capped at `HO_CAP`). Covered by `test/closure-capture.test.js` and `test/phase6-taint.test.js`.
|
|
17
|
+
- **Recursion via fixed point.** `runTaintEngine` runs a multi-pass fixed-point loop (`MAX_FP_ITERS=3`) until the summary cache stabilizes, so recursive cycles and call chains converge instead of under-approximating on a single pass.
|
|
18
|
+
|
|
19
|
+
## Scope — what we still do NOT model (today)
|
|
20
|
+
|
|
21
|
+
- **Call-string (k>1) context-sensitivity.** Context is the *value* abstraction — which params are tainted at entry — not the call stack. Two call paths that reach a helper with the same tainted-arg shape share a summary. Entry-state granularity is also param-level, not arbitrary access paths (`f(obj)` with `obj.a` tainted ≡ `obj.b` tainted).
|
|
22
|
+
- **Contexts beyond the per-function cap.** Once a function has been computed under `AGENTIC_SECURITY_KCFA_MAX_CONTEXTS` distinct tainted-arg shapes, further shapes fall back to the empty-entry summary (an under-approximation, bounded on purpose).
|
|
18
23
|
- **Implicit flow.** `implicit-flow.js` exists for `if (tainted) { x = "yes" }` propagation but is conservative-by-default.
|
|
19
24
|
|
|
25
|
+
## Precision: centralized SSRF/path guard recognition
|
|
26
|
+
|
|
27
|
+
`engine.js` `dropGuardedFindings(findings, fc)` runs after all detectors and drops a CWE-918 (SSRF) finding when the sink window has a host allow/deny check (deny/allow-list, `getHost`/`hostname` comparison, RFC1918/`169.254.169.254` prefix check, `ipaddress`/`getaddrinfo`/`ssrf-req-filter`), or a CWE-22 (path) finding when the window has a containment guard (`basename`/`GetFileName`/`secure_filename`/`send_from_directory`, or canonicalize+`startsWith`). It's the single source of truth so every emitter (regex, structural, per-language flow, PY-SAST, CSHARP, GO) is treated uniformly. The window is **comment-stripped** (a "no allow-list / 169.254…" vuln comment must not read as a guard). Opt out: `AGENTIC_SECURITY_NO_GUARD_RECOGNITION=1`.
|
|
28
|
+
|
|
20
29
|
## Entry points
|
|
21
30
|
|
|
22
31
|
- `runTaintEngine(perFileIR, callGraph, opts)` — the public entry. Called from `engine.js` when `AGENTIC_SECURITY_DEEP=1` (or auto-enabled outside CI).
|
|
23
32
|
- `applyPathFeasibility` — constant-fold pass that runs before the worklist.
|
|
24
33
|
- `annotateBackwardSlices` — backward-slice annotation for already-emitted findings.
|
|
34
|
+
- `annotateProvenClean(findings, perFileIR)` (`proven-clean.js`) — proves a SQL sink is reached only through a parameterizer; sets `provenClean`. Wired by default in `runDeepAnalysis` (opt out: `AGENTIC_SECURITY_NO_PROOF_GATE=1`).
|
|
35
|
+
- `annotateProofGate(findings)` (`proof-gate.js`) — the precision gate. Consolidates `provenClean` + `_provenUnreachable` into one `finding.proof = { verdict, reasons }` and applies a **recall-preserving demotion** (lowers `confidence` + `confidenceTier` + `exploitabilityTier`, never `severity`). Runs in `engine.js` after confidence/exploitability, before mitigation/composite-risk. Default on.
|
|
25
36
|
|
|
26
37
|
## Configuration / opt-in
|
|
27
38
|
|
|
@@ -29,6 +40,7 @@ Layer-2 taint engine. Walks the Layer-1 IR (`../ir/`) with field-sensitive forwa
|
|
|
29
40
|
- `AGENTIC_SECURITY_DEEP_TIMEOUT_MS` — global walltime budget (default 300_000).
|
|
30
41
|
- `AGENTIC_SECURITY_DEEP_FN_LIMIT` — function-count budget (default 5000).
|
|
31
42
|
- `AGENTIC_SECURITY_DEEP_IN_CI=1` — also enable in CI (off by default; CI runs are time-bounded).
|
|
43
|
+
- `AGENTIC_SECURITY_KCFA_MAX_CONTEXTS` — distinct non-empty entry contexts kept per function (default 16; 0 = monovariant).
|
|
32
44
|
|
|
33
45
|
## Gotchas
|
|
34
46
|
|
package/src/dataflow/catalog.js
CHANGED
|
@@ -99,6 +99,15 @@ export const CATALOG = [
|
|
|
99
99
|
{ kind: 'sanitizer', id: 'js-String-coerce', language: 'js', match: { type: 'call', callee: 'String' }, effect: 'strip', appliesTo: ['mongo-operator'] },
|
|
100
100
|
{ kind: 'sanitizer', id: 'js-validator-escape', language: 'js', match: { type: 'call', callee: 'escape' }, effect: 'strip', appliesTo: ['xss'] },
|
|
101
101
|
{ kind: 'sanitizer', id: 'js-strip_tags', language: 'js', match: { type: 'call', callee: 'stripTags' }, effect: 'strip', appliesTo: ['xss'] },
|
|
102
|
+
// Schema-validation libraries (#7). Scoped to NoSQL/operator injection ONLY:
|
|
103
|
+
// validating that input matches a typed shape defeats operator injection
|
|
104
|
+
// (a `{$gt:''}` object can't satisfy `z.string()`). It does NOT sanitize the
|
|
105
|
+
// value for XSS/SQL/cmd — a validated string is still a payload — so these
|
|
106
|
+
// are deliberately NOT tagged for those families (doing so would cause false
|
|
107
|
+
// negatives). Only distinctive callees, to avoid colliding with JSON.parse.
|
|
108
|
+
{ kind: 'sanitizer', id: 'js-zod-safeParse', language: 'js', match: { type: 'call', callee: 'safeParse' }, effect: 'strip', appliesTo: ['mongo-operator'] },
|
|
109
|
+
{ kind: 'sanitizer', id: 'js-zod-parseAsync', language: 'js', match: { type: 'call', callee: 'parseAsync' }, effect: 'strip', appliesTo: ['mongo-operator'] },
|
|
110
|
+
{ kind: 'sanitizer', id: 'js-class-validator', language: 'js', match: { type: 'call', callee: 'validateOrReject' }, effect: 'strip', appliesTo: ['mongo-operator'] },
|
|
102
111
|
|
|
103
112
|
// ─── SOURCES (Python — Flask / FastAPI / Django) ──────────────────────────
|
|
104
113
|
{ kind: 'source', id: 'py-flask-request-args', language: 'py', framework: 'flask', match: { type: 'member', object: 'request', prop: 'args' }, label: 'request.args' },
|
package/src/dataflow/engine.js
CHANGED
|
@@ -215,7 +215,8 @@ function step(node, stateIn, callContext) {
|
|
|
215
215
|
const calleeName = node.source && node.source.kind === 'call' && typeof node.source.callee === 'string'
|
|
216
216
|
? node.source.callee : null;
|
|
217
217
|
if (target && calleeName && callContext._summaryCache && callContext._callGraph) {
|
|
218
|
-
const
|
|
218
|
+
const _callerFile = (callContext._currentFnQid || '').split('::')[0] || undefined;
|
|
219
|
+
const resolved = callContext._callGraph.resolve ? callContext._callGraph.resolve(calleeName, _callerFile) : null;
|
|
219
220
|
const fn = resolved && resolved.qid ? resolved : null;
|
|
220
221
|
const qid = resolved && (resolved.qid || resolved);
|
|
221
222
|
if (typeof qid === 'string') {
|
|
@@ -322,8 +323,9 @@ function step(node, stateIn, callContext) {
|
|
|
322
323
|
// Object.assign(target, tainted) → target becomes tainted in caller.
|
|
323
324
|
if (callContext._summaryCache && callContext._callGraph
|
|
324
325
|
&& typeof node.callee === 'string') {
|
|
326
|
+
const _callerFile = (callContext._currentFnQid || '').split('::')[0] || undefined;
|
|
325
327
|
const resolved = callContext._callGraph.resolve
|
|
326
|
-
? callContext._callGraph.resolve(node.callee) : null;
|
|
328
|
+
? callContext._callGraph.resolve(node.callee, _callerFile) : null;
|
|
327
329
|
const fn = resolved && resolved.qid ? resolved : null;
|
|
328
330
|
const qid = resolved && (resolved.qid || resolved);
|
|
329
331
|
if (typeof qid === 'string' && fn && Array.isArray(fn.params)) {
|
|
@@ -331,7 +333,31 @@ function step(node, stateIn, callContext) {
|
|
|
331
333
|
const entry = paramNames.length
|
|
332
334
|
? entryStateFromCall(paramNames, node.args || [], state)
|
|
333
335
|
: new Set();
|
|
334
|
-
|
|
336
|
+
let sum = callContext._summaryCache.get(qid, entry);
|
|
337
|
+
// FR-SEM-2: context-sensitive lazy compute at the plain-call site,
|
|
338
|
+
// mirroring the assign-call site. On a miss for a NON-empty entry,
|
|
339
|
+
// compute the callee's summary UNDER that tainted-arg context so a
|
|
340
|
+
// param mutated only when called with user input is detected here
|
|
341
|
+
// too (not just when the call's result is assigned). Bounded by the
|
|
342
|
+
// SummaryCache context cap.
|
|
343
|
+
if (!sum && entry.size && fn && fn.cfg) {
|
|
344
|
+
sum = callContext._summaryCache.compute(qid, entry, () => {
|
|
345
|
+
const inner = {
|
|
346
|
+
_findings: [], _taintSources: [], _returnTainted: false,
|
|
347
|
+
_stack: new Set(), deadlineMs: callContext.deadlineMs,
|
|
348
|
+
_summaryCache: callContext._summaryCache,
|
|
349
|
+
_callGraph: callContext._callGraph,
|
|
350
|
+
_mutatedParamsOut: new Set(),
|
|
351
|
+
};
|
|
352
|
+
try { analyzeFunction(fn, entry, inner); } catch {}
|
|
353
|
+
return {
|
|
354
|
+
returnTainted: !!inner._returnTainted,
|
|
355
|
+
mutatedParams: inner._mutatedParamsOut || new Set(),
|
|
356
|
+
taintedGlobals: new Set(),
|
|
357
|
+
findings: [],
|
|
358
|
+
};
|
|
359
|
+
});
|
|
360
|
+
}
|
|
335
361
|
if (sum && sum.mutatedParams && sum.mutatedParams.size) {
|
|
336
362
|
const mutated = callContext._summaryCache.applyAtCallSite(
|
|
337
363
|
sum, paramNames, node.args || [], state);
|
|
@@ -685,7 +711,7 @@ export function runTaintEngine(perFileIR, callGraph, opts = {}) {
|
|
|
685
711
|
if (Date.now() > deadlineMs) break;
|
|
686
712
|
const inv = hoInvocations[hi];
|
|
687
713
|
if (!inv.callee || !inv.taintedParam) continue;
|
|
688
|
-
const resolved = callGraph.resolve ? callGraph.resolve(inv.callee) : null;
|
|
714
|
+
const resolved = callGraph.resolve ? callGraph.resolve(inv.callee, fn && fn.file) : null;
|
|
689
715
|
const cbFn = resolved && resolved.qid ? resolved : null;
|
|
690
716
|
if (!cbFn || !cbFn.params || !cbFn.params.length) continue;
|
|
691
717
|
const cbEntry = new Set([cbFn.params[inv.paramIndex || 0]]);
|
package/src/dataflow/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Layer 2 entry point.
|
|
2
2
|
import { runTaintEngine } from './engine.js';
|
|
3
|
+
import { annotateProvenClean } from './proven-clean.js';
|
|
3
4
|
import { CATALOG, matchSource, matchSinkOrSanitizer, _catalogSize } from './catalog.js';
|
|
4
5
|
import { applyPathFeasibility } from './path-feasibility.js';
|
|
5
6
|
import { SummaryCache, entryStateFromCall } from './summaries.js';
|
|
@@ -114,6 +115,13 @@ export function runDeepAnalysis(perFileIR, callGraph, opts = {}) {
|
|
|
114
115
|
if (process.env.AGENTIC_SECURITY_BACKWARD_SLICE === '1') {
|
|
115
116
|
findings = annotateBackwardSlices(findings, perFileIR, callGraph);
|
|
116
117
|
}
|
|
118
|
+
// Roadmap #6 — flow-proof: prove SQL sinks reached only through a
|
|
119
|
+
// parameterizer (`provenClean`). Runs by default in the deep pass; it only
|
|
120
|
+
// touches IR-TAINT SQL findings and never drops anything. The proof-gate
|
|
121
|
+
// annotator (engine.js) consolidates this into the demotion verdict.
|
|
122
|
+
if (process.env.AGENTIC_SECURITY_NO_PROOF_GATE !== '1') {
|
|
123
|
+
try { findings = annotateProvenClean(findings, perFileIR); } catch { /* proof failure must not fail the scan */ }
|
|
124
|
+
}
|
|
117
125
|
// v0.70 #6 — probabilistic / soft taint. Walks each finding's trace +
|
|
118
126
|
// chain, multiplies (1 - effectiveness) across sanitizers, demotes
|
|
119
127
|
// below-threshold findings to lower severity (never drops).
|