@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.
Files changed (125) hide show
  1. package/CHANGELOG.md +404 -0
  2. package/dist/178.index.js +1 -1
  3. package/dist/384.index.js +1 -1
  4. package/dist/637.index.js +1 -1
  5. package/dist/838.index.js +1 -1
  6. package/dist/agentic-security.mjs +84 -84
  7. package/dist/agentic-security.mjs.sha256 +1 -1
  8. package/package.json +12 -6
  9. package/src/.agentic-security/dpia.md +26 -0
  10. package/src/.agentic-security/pqc-migration-plan.json +80 -0
  11. package/src/.agentic-security/pqc-migration-plan.md +32 -0
  12. package/src/.agentic-security/sbom-history/0775d96ba4cf814520d02760cfb3010760c7684f.json +6 -0
  13. package/src/.agentic-security/sbom-history/29300441d3460832137a8e51a92b74068cad2f15.json +6 -0
  14. package/src/.agentic-security/sbom-history/3852ad2aa0e50951bed0c930c29d1861aa13d048.json +6 -0
  15. package/src/.agentic-security/sbom-history/3d96e2daec97e3226c9679bac6e64a89ca10bfe9.json +6 -0
  16. package/src/.agentic-security/sbom-history/5f0b136622fce09b469a1a6137c04d5b18652ea4.json +6 -0
  17. package/src/.agentic-security/sbom-history/64e30595d447b62344d0d9200760269df2095332.json +6 -0
  18. package/src/.agentic-security/sbom-history/71f3241902c9e7437764e3caa046ba8a3bcdd32a.json +6 -0
  19. package/src/.agentic-security/sbom-history/99c372cdc33ecc9dde92960b4ffadf7775860e61.json +6 -0
  20. package/src/.agentic-security/sbom-history/9c93b15e8cf3ff2ddb8cdae92371b82e178b463c.json +6 -0
  21. package/src/.agentic-security/sbom-history/a3544abf1863d71776b61302ca74d9ead2b26a9f.json +6 -0
  22. package/src/.agentic-security/sbom-history/dca15abdec43c508aa342db86dc5db8d7f01fbbe.json +6 -0
  23. package/src/.agentic-security/threat-model.json +3702 -0
  24. package/src/.agentic-security/threat-model.md +118 -0
  25. package/src/dataflow/.agentic-security/dpia.md +26 -0
  26. package/src/dataflow/.agentic-security/sbom-history/15d7c4d20f9d968ebec29445c9e9b3fc6f74e6a1.json +6 -0
  27. package/src/dataflow/.agentic-security/sbom-history/3852ad2aa0e50951bed0c930c29d1861aa13d048.json +6 -0
  28. package/src/dataflow/.agentic-security/sbom-history/73166872888d9ddcbe98645af818ecc7d8917b07.json +6 -0
  29. package/src/dataflow/.agentic-security/sbom-history/8869fe64035bec0152d92ece961e9369d8637076.json +6 -0
  30. package/src/dataflow/.agentic-security/sbom-history/9c93b15e8cf3ff2ddb8cdae92371b82e178b463c.json +6 -0
  31. package/src/dataflow/.agentic-security/sbom-history/b7ac2dada4a9216ccfe8969fc57f988c83f46975.json +6 -0
  32. package/src/dataflow/.agentic-security/threat-model.json +161 -0
  33. package/src/dataflow/.agentic-security/threat-model.md +43 -0
  34. package/src/dataflow/CLAUDE.md +17 -5
  35. package/src/dataflow/catalog.js +9 -0
  36. package/src/dataflow/engine.js +30 -4
  37. package/src/dataflow/index.js +8 -0
  38. package/src/dataflow/proof-gate.js +95 -0
  39. package/src/dataflow/summaries.js +44 -5
  40. package/src/engine.js +199 -5
  41. package/src/ir/.agentic-security/dpia.md +26 -0
  42. package/src/ir/.agentic-security/exploit-bundles.json +77 -0
  43. package/src/ir/.agentic-security/sbom-history/73166872888d9ddcbe98645af818ecc7d8917b07.json +6 -0
  44. package/src/ir/.agentic-security/sbom-history/b5f468a158f6a145aedd8680841c106b9809f16b.json +6 -0
  45. package/src/ir/.agentic-security/threat-model.json +143 -0
  46. package/src/ir/.agentic-security/threat-model.md +39 -0
  47. package/src/ir/CLAUDE.md +1 -0
  48. package/src/ir/callgraph.js +12 -1
  49. package/src/ir/tree-sitter-loader.js +108 -0
  50. package/src/posture/.agentic-security/dpia.md +26 -0
  51. package/src/posture/.agentic-security/pqc-migration-plan.json +65 -0
  52. package/src/posture/.agentic-security/pqc-migration-plan.md +30 -0
  53. package/src/posture/.agentic-security/sbom-history/0724c133d2943c87555695b5b2adcfcfc3373a2d.json +6 -0
  54. package/src/posture/.agentic-security/sbom-history/7d45b5e03804aac084b4a2b4dc8c6f10107d2005.json +6 -0
  55. package/src/posture/.agentic-security/sbom-history/99c372cdc33ecc9dde92960b4ffadf7775860e61.json +6 -0
  56. package/src/posture/.agentic-security/sbom-history/b7ac2dada4a9216ccfe8969fc57f988c83f46975.json +6 -0
  57. package/src/posture/.agentic-security/threat-model.json +2038 -0
  58. package/src/posture/.agentic-security/threat-model.md +73 -0
  59. package/src/posture/auditor-walkthrough.js +1 -1
  60. package/src/posture/corpus-status.js +74 -0
  61. package/src/posture/coverage-report.js +113 -0
  62. package/src/posture/holdout-eval.js +57 -0
  63. package/src/posture/pr-augment.js +1 -1
  64. package/src/posture/router.js +37 -7
  65. package/src/report/.agentic-security/dpia.md +26 -0
  66. package/src/report/.agentic-security/sbom-history/7d45b5e03804aac084b4a2b4dc8c6f10107d2005.json +6 -0
  67. package/src/report/.agentic-security/sbom-history/f94be839aa6a1011f53da016416a561698b8f338.json +6 -0
  68. package/src/report/.agentic-security/threat-model.json +7 -0
  69. package/src/report/.agentic-security/threat-model.md +22 -0
  70. package/src/report/index.js +18 -1
  71. package/src/sast/.agentic-security/dpia.md +26 -0
  72. package/src/sast/.agentic-security/pqc-migration-plan.json +65 -0
  73. package/src/sast/.agentic-security/pqc-migration-plan.md +30 -0
  74. package/src/sast/.agentic-security/sbom-history/043a7b401c68f5a298c83d4c42e94f118ff2a89a.json +6 -0
  75. package/src/sast/.agentic-security/sbom-history/0775d96ba4cf814520d02760cfb3010760c7684f.json +6 -0
  76. package/src/sast/.agentic-security/sbom-history/20d77ad7363a82777d506dedbbb1ecfed52f094a.json +6 -0
  77. package/src/sast/.agentic-security/sbom-history/29300441d3460832137a8e51a92b74068cad2f15.json +6 -0
  78. package/src/sast/.agentic-security/sbom-history/3852ad2aa0e50951bed0c930c29d1861aa13d048.json +6 -0
  79. package/src/sast/.agentic-security/sbom-history/3c6b3205f04e26f7654943d465281d00e0fa395e.json +6 -0
  80. package/src/sast/.agentic-security/sbom-history/3d96e2daec97e3226c9679bac6e64a89ca10bfe9.json +6 -0
  81. package/src/sast/.agentic-security/sbom-history/5282502e090013219eb006f7e02d8c983bc29c8e.json +6 -0
  82. package/src/sast/.agentic-security/sbom-history/5f0b136622fce09b469a1a6137c04d5b18652ea4.json +6 -0
  83. package/src/sast/.agentic-security/sbom-history/64e30595d447b62344d0d9200760269df2095332.json +6 -0
  84. package/src/sast/.agentic-security/sbom-history/71f3241902c9e7437764e3caa046ba8a3bcdd32a.json +6 -0
  85. package/src/sast/.agentic-security/sbom-history/73514b485d4770f3c5ee57d87338bccd1c61d8b7.json +6 -0
  86. package/src/sast/.agentic-security/sbom-history/96fa584fc3134512237d58aac63d6f3778b0cbcb.json +6 -0
  87. package/src/sast/.agentic-security/sbom-history/99c372cdc33ecc9dde92960b4ffadf7775860e61.json +6 -0
  88. package/src/sast/.agentic-security/sbom-history/a3544abf1863d71776b61302ca74d9ead2b26a9f.json +6 -0
  89. package/src/sast/.agentic-security/sbom-history/a4a34ab8b3d758de2adc8c3dc3e42d4cb0db00a3.json +6 -0
  90. package/src/sast/.agentic-security/sbom-history/ac236ec3602cfc8fb133f389ec3687e409084673.json +6 -0
  91. package/src/sast/.agentic-security/sbom-history/b57b3e1292f1f9f0de6c5a34a436e330c78008a3.json +6 -0
  92. package/src/sast/.agentic-security/sbom-history/dca15abdec43c508aa342db86dc5db8d7f01fbbe.json +6 -0
  93. package/src/sast/.agentic-security/sbom-history/dcbfd4935922dd165093c08a1003c338eed937c5.json +6 -0
  94. package/src/sast/.agentic-security/sbom-history/fa017f725615b0293814344c8ef7dfeb06775ca0.json +6 -0
  95. package/src/sast/.agentic-security/threat-model.json +816 -0
  96. package/src/sast/.agentic-security/threat-model.md +91 -0
  97. package/src/sast/CLAUDE.md +9 -3
  98. package/src/sast/code-injection-multilang.js +117 -0
  99. package/src/sast/crypto-protocol.js +43 -1
  100. package/src/sast/csharp-structural.js +65 -0
  101. package/src/sast/csharp.js +3 -0
  102. package/src/sast/csrf.js +24 -3
  103. package/src/sast/csv-injection.js +84 -0
  104. package/src/sast/frontend-hygiene.js +106 -0
  105. package/src/sast/go-structural.js +60 -0
  106. package/src/sast/java-structural.js +81 -0
  107. package/src/sast/js-framework-structural.js +115 -0
  108. package/src/sast/kotlin.js +72 -0
  109. package/src/sast/ldap-injection.js +73 -17
  110. package/src/sast/open-redirect.js +47 -5
  111. package/src/sast/php.js +35 -0
  112. package/src/sast/python-structural.js +83 -0
  113. package/src/sast/redos-nfa.js +75 -0
  114. package/src/sast/response-splitting.js +48 -19
  115. package/src/sast/ruby.js +38 -0
  116. package/src/sast/secret-concat.js +60 -0
  117. package/src/sast/ssrf-cloud-metadata.js +13 -0
  118. package/src/sast/stored-taint.js +88 -0
  119. package/src/sast/tree-sitter-sinks.js +62 -0
  120. package/src/sast/weak-password-hash.js +28 -0
  121. package/src/sast/weak-randomness.js +46 -5
  122. package/src/sast/wrong-context-sanitizer.js +94 -0
  123. package/src/sast/xpath-injection.js +30 -6
  124. package/src/sast/xss-reflected-multilang.js +116 -0
  125. 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,6 @@
1
+ {
2
+ "sha": "15d7c4d20f9d968ebec29445c9e9b3fc6f74e6a1",
3
+ "ts": "2026-05-31T15:22:34.931Z",
4
+ "componentCount": 0,
5
+ "components": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sha": "3852ad2aa0e50951bed0c930c29d1861aa13d048",
3
+ "ts": "2026-05-31T18:39:51.074Z",
4
+ "componentCount": 0,
5
+ "components": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sha": "73166872888d9ddcbe98645af818ecc7d8917b07",
3
+ "ts": "2026-05-31T15:37:46.482Z",
4
+ "componentCount": 0,
5
+ "components": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sha": "8869fe64035bec0152d92ece961e9369d8637076",
3
+ "ts": "2026-05-31T13:34:26.146Z",
4
+ "componentCount": 0,
5
+ "components": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sha": "9c93b15e8cf3ff2ddb8cdae92371b82e178b463c",
3
+ "ts": "2026-05-31T04:45:23.979Z",
4
+ "componentCount": 0,
5
+ "components": []
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sha": "b7ac2dada4a9216ccfe8969fc57f988c83f46975",
3
+ "ts": "2026-05-31T05:26:44.996Z",
4
+ "componentCount": 0,
5
+ "components": []
6
+ }
@@ -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
@@ -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
- - **k=1 monovariant interprocedural return-taint.** `SummaryCache` (`summaries.js`) holds one summary per function under empty entry state. At an assign-from-call site, if the resolved callee's summary says `returnTainted`, the LHS becomes tainted. Premortem-derived; was previously dead code.
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 — what we do NOT model (today)
13
+ ## Scope — now modelled (was previously listed as gaps; closed in v0.66)
14
14
 
15
- - **Arbitrary entry-taint-state context-sensitivity.** Each function gets ONE summary, computed under empty entry. A function that's pure when called with clean args but vulnerable when called with tainted args is modelled as the empty-state result. Track FR-SEM-2 to lift this.
16
- - **Mutated-parameter taint at call sites.** The `SummaryCache.applyAtCallSite` helper exists for it; the engine doesn't consult it yet. If you want a helper that mutates its argument (`Object.assign(target, tainted)`) to taint the caller's `target`, this is the modelling gap.
17
- - **Higher-order taint flow** partial. `higher-order.js` propagates taint into `arr.map(fn)` / `promise.then(fn)` callbacks at the IR level, but the recorded `_higherOrderInvocations` aren't fed back into the worklist yet.
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
 
@@ -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' },
@@ -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 resolved = callContext._callGraph.resolve ? callContext._callGraph.resolve(calleeName) : null;
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
- const sum = callContext._summaryCache.get(qid, entry);
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]]);
@@ -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).