@clear-capabilities/agentic-security-scanner 0.74.0

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 (331) hide show
  1. package/CHANGELOG.md +1580 -0
  2. package/bin/.agentic-security/findings.json +1577 -0
  3. package/bin/.agentic-security/last-scan.json +1577 -0
  4. package/bin/.agentic-security/last-scan.json.sig +1 -0
  5. package/bin/.agentic-security/scan-history.json +465 -0
  6. package/bin/.agentic-security/streak.json +25 -0
  7. package/bin/agentic-security-audit.js +198 -0
  8. package/bin/agentic-security-consistency.js +80 -0
  9. package/bin/agentic-security-diff.js +136 -0
  10. package/bin/agentic-security-lsp.js +12 -0
  11. package/bin/agentic-security-mcp.js +40 -0
  12. package/bin/agentic-security-rule.js +153 -0
  13. package/bin/agentic-security.js +1683 -0
  14. package/dist/117.index.js +207 -0
  15. package/dist/178.index.js +250 -0
  16. package/dist/218.index.js +793 -0
  17. package/dist/227.index.js +192 -0
  18. package/dist/301.index.js +167 -0
  19. package/dist/384.index.js +18 -0
  20. package/dist/476.index.js +126 -0
  21. package/dist/513.index.js +373 -0
  22. package/dist/520.index.js +13 -0
  23. package/dist/601.index.js +1038 -0
  24. package/dist/634.index.js +1892 -0
  25. package/dist/637.index.js +216 -0
  26. package/dist/660.index.js +131 -0
  27. package/dist/675.index.js +451 -0
  28. package/dist/826.index.js +188 -0
  29. package/dist/830.index.js +133 -0
  30. package/dist/agentic-security.mjs +272 -0
  31. package/dist/agentic-security.mjs.sha256 +1 -0
  32. package/dist/calibration-seed.json +27 -0
  33. package/package.json +77 -0
  34. package/src/.agentic-security/findings.json +80844 -0
  35. package/src/.agentic-security/last-scan.json +80844 -0
  36. package/src/.agentic-security/last-scan.json.sig +1 -0
  37. package/src/.agentic-security/scan-history.json +8408 -0
  38. package/src/.agentic-security/streak.json +26 -0
  39. package/src/badge.js +188 -0
  40. package/src/compare.js +203 -0
  41. package/src/dataflow/.agentic-security/findings.json +3487 -0
  42. package/src/dataflow/.agentic-security/last-scan.json +3487 -0
  43. package/src/dataflow/.agentic-security/last-scan.json.sig +1 -0
  44. package/src/dataflow/.agentic-security/scan-history.json +735 -0
  45. package/src/dataflow/.agentic-security/streak.json +24 -0
  46. package/src/dataflow/CLAUDE.md +38 -0
  47. package/src/dataflow/access-paths.js +172 -0
  48. package/src/dataflow/async-sequencing.js +177 -0
  49. package/src/dataflow/backward.js +201 -0
  50. package/src/dataflow/catalog-expanded.js +485 -0
  51. package/src/dataflow/catalog.js +659 -0
  52. package/src/dataflow/cross-repo.js +219 -0
  53. package/src/dataflow/engine.js +588 -0
  54. package/src/dataflow/exception-flow.js +116 -0
  55. package/src/dataflow/exploit-prover.js +187 -0
  56. package/src/dataflow/higher-order.js +221 -0
  57. package/src/dataflow/ifds.js +347 -0
  58. package/src/dataflow/implicit-flow.js +129 -0
  59. package/src/dataflow/incremental.js +229 -0
  60. package/src/dataflow/index.js +181 -0
  61. package/src/dataflow/numeric-domain.js +192 -0
  62. package/src/dataflow/path-feasibility.js +114 -0
  63. package/src/dataflow/points-to.js +337 -0
  64. package/src/dataflow/polyglot.js +190 -0
  65. package/src/dataflow/proven-clean.js +159 -0
  66. package/src/dataflow/receiver-context.js +76 -0
  67. package/src/dataflow/sanitizer-proof.js +154 -0
  68. package/src/dataflow/soft-taint.js +140 -0
  69. package/src/dataflow/string-domain.js +234 -0
  70. package/src/dataflow/stub-aware-filter.js +100 -0
  71. package/src/dataflow/summaries.js +132 -0
  72. package/src/dataflow/symbolic-exec.js +238 -0
  73. package/src/dataflow/tabulation.js +135 -0
  74. package/src/engine.js +7763 -0
  75. package/src/history-scan.js +229 -0
  76. package/src/index.js +3 -0
  77. package/src/integrations/.agentic-security/findings.json +1504 -0
  78. package/src/integrations/.agentic-security/last-scan.json +1504 -0
  79. package/src/integrations/.agentic-security/scan-history.json +40 -0
  80. package/src/integrations/.agentic-security/streak.json +21 -0
  81. package/src/integrations/index.js +321 -0
  82. package/src/integrations/tickets.js +200 -0
  83. package/src/ir/.agentic-security/findings.json +3036 -0
  84. package/src/ir/.agentic-security/last-scan.json +3036 -0
  85. package/src/ir/.agentic-security/last-scan.json.sig +1 -0
  86. package/src/ir/.agentic-security/scan-history.json +364 -0
  87. package/src/ir/.agentic-security/streak.json +23 -0
  88. package/src/ir/CLAUDE.md +172 -0
  89. package/src/ir/callgraph.js +73 -0
  90. package/src/ir/class-hierarchy.js +195 -0
  91. package/src/ir/index.js +152 -0
  92. package/src/ir/parser-cs.js +260 -0
  93. package/src/ir/parser-java.js +286 -0
  94. package/src/ir/parser-js.js +413 -0
  95. package/src/ir/parser-kt.js +258 -0
  96. package/src/ir/parser-py-cst.js +136 -0
  97. package/src/ir/parser-py.helper.py +501 -0
  98. package/src/ir/parser-py.js +312 -0
  99. package/src/ir/ssa.js +315 -0
  100. package/src/ir/type-stubs.js +288 -0
  101. package/src/leaderboard.js +152 -0
  102. package/src/llm-validator/.agentic-security/findings.json +1891 -0
  103. package/src/llm-validator/.agentic-security/last-scan.json +1891 -0
  104. package/src/llm-validator/.agentic-security/last-scan.json.sig +1 -0
  105. package/src/llm-validator/.agentic-security/scan-history.json +168 -0
  106. package/src/llm-validator/.agentic-security/streak.json +20 -0
  107. package/src/llm-validator/consistency.js +141 -0
  108. package/src/llm-validator/index.js +437 -0
  109. package/src/lsp/.agentic-security/findings.json +28 -0
  110. package/src/lsp/.agentic-security/last-scan.json +28 -0
  111. package/src/lsp/.agentic-security/scan-history.json +79 -0
  112. package/src/lsp/.agentic-security/streak.json +22 -0
  113. package/src/lsp/server.js +275 -0
  114. package/src/mcp/.agentic-security/findings.json +8358 -0
  115. package/src/mcp/.agentic-security/last-scan.json +8358 -0
  116. package/src/mcp/.agentic-security/last-scan.json.sig +1 -0
  117. package/src/mcp/.agentic-security/scan-history.json +1125 -0
  118. package/src/mcp/.agentic-security/streak.json +22 -0
  119. package/src/mcp/CLAUDE.md +54 -0
  120. package/src/mcp/audit.js +136 -0
  121. package/src/mcp/redact.js +75 -0
  122. package/src/mcp/server.js +158 -0
  123. package/src/mcp/stdio.js +83 -0
  124. package/src/mcp/tools.js +940 -0
  125. package/src/mcp/validate.js +49 -0
  126. package/src/personality.js +164 -0
  127. package/src/poc-video.js +239 -0
  128. package/src/posture/.agentic-security/findings.json +51239 -0
  129. package/src/posture/.agentic-security/last-scan.json +51239 -0
  130. package/src/posture/.agentic-security/last-scan.json.sig +1 -0
  131. package/src/posture/.agentic-security/scan-history.json +5557 -0
  132. package/src/posture/.agentic-security/streak.json +24 -0
  133. package/src/posture/CLAUDE.md +42 -0
  134. package/src/posture/adversarial-self-test.js +114 -0
  135. package/src/posture/adversary-agent.js +204 -0
  136. package/src/posture/agents-memory.js +135 -0
  137. package/src/posture/ai-code-fingerprint.js +171 -0
  138. package/src/posture/aibom.js +284 -0
  139. package/src/posture/api-inventory.js +96 -0
  140. package/src/posture/attack-playbooks.js +305 -0
  141. package/src/posture/auditor-agent.js +115 -0
  142. package/src/posture/auth-posture-import.js +135 -0
  143. package/src/posture/baseline-compare.js +114 -0
  144. package/src/posture/blast-radius.js +836 -0
  145. package/src/posture/bounty-prediction.js +141 -0
  146. package/src/posture/business-logic.js +239 -0
  147. package/src/posture/calibration-drift.js +93 -0
  148. package/src/posture/calibration-seed.json +27 -0
  149. package/src/posture/calibration.js +204 -0
  150. package/src/posture/clustering.js +75 -0
  151. package/src/posture/concurrency-checker.js +265 -0
  152. package/src/posture/confidence.js +65 -0
  153. package/src/posture/container-runtime.js +149 -0
  154. package/src/posture/counterfactual.js +109 -0
  155. package/src/posture/cross-lang-graphql.js +165 -0
  156. package/src/posture/cross-lang-grpc.js +166 -0
  157. package/src/posture/cross-lang-meta.js +101 -0
  158. package/src/posture/cross-lang-openapi.js +187 -0
  159. package/src/posture/cross-lang-orm.js +153 -0
  160. package/src/posture/cross-lang-queues.js +210 -0
  161. package/src/posture/crown-jewels.js +110 -0
  162. package/src/posture/custom-rules.js +361 -0
  163. package/src/posture/cve-alert-daemon.js +433 -0
  164. package/src/posture/cve-lookup.js +129 -0
  165. package/src/posture/dead-code.js +430 -0
  166. package/src/posture/defender-agent.js +158 -0
  167. package/src/posture/deploy-platform.js +204 -0
  168. package/src/posture/detector-fuzz.js +61 -0
  169. package/src/posture/deterministic.js +99 -0
  170. package/src/posture/drift.js +165 -0
  171. package/src/posture/epss.js +156 -0
  172. package/src/posture/exploitability-probability.js +212 -0
  173. package/src/posture/exploitability.js +121 -0
  174. package/src/posture/feature-flags.js +110 -0
  175. package/src/posture/finding-defaults.js +132 -0
  176. package/src/posture/fix-history.js +411 -0
  177. package/src/posture/fix-plan.js +121 -0
  178. package/src/posture/fix-verify-loop.js +157 -0
  179. package/src/posture/fix-verify.js +130 -0
  180. package/src/posture/flow-narration.js +105 -0
  181. package/src/posture/grader-calibration.js +156 -0
  182. package/src/posture/harness-discovery.js +113 -0
  183. package/src/posture/holdout-eval.js +144 -0
  184. package/src/posture/iac-reachability.js +163 -0
  185. package/src/posture/iam-policy.js +128 -0
  186. package/src/posture/integrity.js +97 -0
  187. package/src/posture/learning.js +166 -0
  188. package/src/posture/license-policy.js +109 -0
  189. package/src/posture/llm-redteam-prompts.js +418 -0
  190. package/src/posture/llm-redteam.js +303 -0
  191. package/src/posture/material-change.js +163 -0
  192. package/src/posture/mitigation-composite.js +55 -0
  193. package/src/posture/mttr.js +91 -0
  194. package/src/posture/network-policy-import.js +126 -0
  195. package/src/posture/path-predicates.js +99 -0
  196. package/src/posture/persona-prioritization.js +153 -0
  197. package/src/posture/poc-cwe-map.js +51 -0
  198. package/src/posture/poc-generator.js +500 -0
  199. package/src/posture/policy-gate.js +174 -0
  200. package/src/posture/pre-incident-archaeology.js +110 -0
  201. package/src/posture/profile.js +93 -0
  202. package/src/posture/reachability-filter.js +42 -0
  203. package/src/posture/regression-test-gen.js +200 -0
  204. package/src/posture/reverse-blast-radius.js +110 -0
  205. package/src/posture/router.js +109 -0
  206. package/src/posture/rule-overrides.js +198 -0
  207. package/src/posture/rule-pack-signing.js +209 -0
  208. package/src/posture/rule-packs.js +143 -0
  209. package/src/posture/rule-synthesis.js +108 -0
  210. package/src/posture/ruleset-version.js +71 -0
  211. package/src/posture/sbom.js +129 -0
  212. package/src/posture/schema-aware-bridge.js +207 -0
  213. package/src/posture/security-trend.js +87 -0
  214. package/src/posture/semantic-clone.js +114 -0
  215. package/src/posture/specification-mining.js +170 -0
  216. package/src/posture/stable-id.js +75 -0
  217. package/src/posture/stack-playbook.js +229 -0
  218. package/src/posture/streak.js +249 -0
  219. package/src/posture/suppressions.js +135 -0
  220. package/src/posture/telemetry-ingest.js +112 -0
  221. package/src/posture/threat-model.js +145 -0
  222. package/src/posture/three-agent-pipeline.js +74 -0
  223. package/src/posture/triage.js +146 -0
  224. package/src/posture/trust-boundary-diagram.js +115 -0
  225. package/src/posture/type-narrowing.js +129 -0
  226. package/src/posture/validator-metrics.js +179 -0
  227. package/src/posture/verifier-ephemeral.js +118 -0
  228. package/src/posture/verifier-target.js +147 -0
  229. package/src/posture/verifier.js +257 -0
  230. package/src/posture/version.js +75 -0
  231. package/src/posture/waf-ingest.js +200 -0
  232. package/src/posture/why-fired.js +141 -0
  233. package/src/pr-comment.js +172 -0
  234. package/src/pr-delta.js +198 -0
  235. package/src/report/.agentic-security/findings.json +79 -0
  236. package/src/report/.agentic-security/last-scan.json +79 -0
  237. package/src/report/.agentic-security/last-scan.json.sig +1 -0
  238. package/src/report/.agentic-security/scan-history.json +332 -0
  239. package/src/report/.agentic-security/streak.json +23 -0
  240. package/src/report/index.js +1136 -0
  241. package/src/report/mascot.js +42 -0
  242. package/src/runScan.js +141 -0
  243. package/src/sast/.agentic-security/findings.json +5051 -0
  244. package/src/sast/.agentic-security/last-scan.json +5051 -0
  245. package/src/sast/.agentic-security/last-scan.json.sig +1 -0
  246. package/src/sast/.agentic-security/scan-history.json +788 -0
  247. package/src/sast/.agentic-security/streak.json +23 -0
  248. package/src/sast/CLAUDE.md +39 -0
  249. package/src/sast/_comment-strip.js +46 -0
  250. package/src/sast/agent-tool-escalation.js +131 -0
  251. package/src/sast/auth-provider.js +171 -0
  252. package/src/sast/authz.js +236 -0
  253. package/src/sast/bench-shape/.agentic-security/findings.json +28 -0
  254. package/src/sast/bench-shape/.agentic-security/last-scan.json +28 -0
  255. package/src/sast/bench-shape/.agentic-security/scan-history.json +24 -0
  256. package/src/sast/bench-shape/.agentic-security/streak.json +22 -0
  257. package/src/sast/bench-shape/index.js +62 -0
  258. package/src/sast/claude-hook-injection.js +199 -0
  259. package/src/sast/claude-md-prompt-injection.js +170 -0
  260. package/src/sast/claude-settings.js +165 -0
  261. package/src/sast/client-side.js +149 -0
  262. package/src/sast/cpp-bench-extras.js +122 -0
  263. package/src/sast/cpp-dataflow.js +430 -0
  264. package/src/sast/cpp.js +248 -0
  265. package/src/sast/csharp.js +152 -0
  266. package/src/sast/csrf.js +82 -0
  267. package/src/sast/dart-flutter.js +173 -0
  268. package/src/sast/db-rls.js +147 -0
  269. package/src/sast/db-taint.js +215 -0
  270. package/src/sast/defi-deep.js +242 -0
  271. package/src/sast/deserialization-gadgets.js +113 -0
  272. package/src/sast/django-hardening.js +230 -0
  273. package/src/sast/env-hygiene.js +125 -0
  274. package/src/sast/fastapi-hardening.js +145 -0
  275. package/src/sast/go-extended.js +84 -0
  276. package/src/sast/host-header.js +106 -0
  277. package/src/sast/index.js +17 -0
  278. package/src/sast/java-ast-folding.js +561 -0
  279. package/src/sast/java-bench-extras.js +708 -0
  280. package/src/sast/java-collection-passthrough.js +178 -0
  281. package/src/sast/java-constant-fold.js +244 -0
  282. package/src/sast/java-deserialization.js +125 -0
  283. package/src/sast/jndi.js +104 -0
  284. package/src/sast/juliet-shape.js +324 -0
  285. package/src/sast/jwt-exp.js +104 -0
  286. package/src/sast/kotlin.js +82 -0
  287. package/src/sast/laravel-hardening.js +198 -0
  288. package/src/sast/ldap-injection.js +100 -0
  289. package/src/sast/llm-owasp.js +465 -0
  290. package/src/sast/llm-stored-prompt.js +103 -0
  291. package/src/sast/llm-trading-agent.js +161 -0
  292. package/src/sast/llm.js +308 -0
  293. package/src/sast/logic.js +140 -0
  294. package/src/sast/mass-assignment.js +101 -0
  295. package/src/sast/mcp-audit.js +242 -0
  296. package/src/sast/mobile-manifest.js +195 -0
  297. package/src/sast/model-load.js +164 -0
  298. package/src/sast/mutation-xss.js +87 -0
  299. package/src/sast/nosql-injection.js +82 -0
  300. package/src/sast/open-redirect.js +119 -0
  301. package/src/sast/php.js +91 -0
  302. package/src/sast/pipeline.js +122 -0
  303. package/src/sast/primary-cwe-java.js +155 -0
  304. package/src/sast/prompt-firewall.js +151 -0
  305. package/src/sast/prompt-template.js +157 -0
  306. package/src/sast/prototype-pollution.js +112 -0
  307. package/src/sast/python-sinks.js +195 -0
  308. package/src/sast/quarkus-hardening.js +102 -0
  309. package/src/sast/rag-poisoning.js +118 -0
  310. package/src/sast/rate-limit.js +128 -0
  311. package/src/sast/response-splitting.js +138 -0
  312. package/src/sast/ruby.js +108 -0
  313. package/src/sast/rust.js +105 -0
  314. package/src/sast/solidity.js +167 -0
  315. package/src/sast/springboot-hardening.js +186 -0
  316. package/src/sast/ssrf-cloud-metadata.js +80 -0
  317. package/src/sast/ssti.js +116 -0
  318. package/src/sast/swift.js +162 -0
  319. package/src/sast/toctou.js +95 -0
  320. package/src/sast/webhook.js +101 -0
  321. package/src/sast/xpath-injection.js +51 -0
  322. package/src/sast/xxe.js +140 -0
  323. package/src/sast/zip-slip.js +200 -0
  324. package/src/sca/base-images.json +45 -0
  325. package/src/sca/container.js +107 -0
  326. package/src/sca/dep-confusion.js +134 -0
  327. package/src/sca/index.js +6 -0
  328. package/src/sca/popular-packages.json +41 -0
  329. package/src/sca/sarif-ingest.js +187 -0
  330. package/src/sca/vuln-function-hints.json +89 -0
  331. package/src/secrets/index.js +4 -0
@@ -0,0 +1,28 @@
1
+ {
2
+ "scanId": "dc3f3a4e-866e-4a96-a3cf-95d740227eca",
3
+ "startedAt": "2026-05-18T14:34:38.677Z",
4
+ "durationMs": 64,
5
+ "scanned": {
6
+ "files": 1,
7
+ "lines": 0
8
+ },
9
+ "findings": [],
10
+ "bundles": [],
11
+ "routes": [],
12
+ "components": [],
13
+ "suppressedCount": 1,
14
+ "blastRadiusSignals": {
15
+ "industry": "generic",
16
+ "industryConfidence": "low",
17
+ "jurisdictions": [],
18
+ "controls": [],
19
+ "estimatedUsers": 50,
20
+ "revenueIndicator": "pre-revenue",
21
+ "hasStripe": false,
22
+ "hasAuth": false,
23
+ "hasUserTable": false,
24
+ "hasPII": false,
25
+ "hasPHI": false,
26
+ "hasS3": false
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "scanId": "dc3f3a4e-866e-4a96-a3cf-95d740227eca",
3
+ "startedAt": "2026-05-18T14:34:38.677Z",
4
+ "durationMs": 64,
5
+ "scanned": {
6
+ "files": 1,
7
+ "lines": 0
8
+ },
9
+ "findings": [],
10
+ "bundles": [],
11
+ "routes": [],
12
+ "components": [],
13
+ "suppressedCount": 1,
14
+ "blastRadiusSignals": {
15
+ "industry": "generic",
16
+ "industryConfidence": "low",
17
+ "jurisdictions": [],
18
+ "controls": [],
19
+ "estimatedUsers": 50,
20
+ "revenueIndicator": "pre-revenue",
21
+ "hasStripe": false,
22
+ "hasAuth": false,
23
+ "hasUserTable": false,
24
+ "hasPII": false,
25
+ "hasPHI": false,
26
+ "hasS3": false
27
+ }
28
+ }
@@ -0,0 +1,24 @@
1
+ [
2
+ {
3
+ "timestamp": "2026-05-18T14:28:11.803Z",
4
+ "label": "scan",
5
+ "total": 0,
6
+ "critical": 0,
7
+ "high": 0,
8
+ "medium": 0,
9
+ "low": 0,
10
+ "kev": 0,
11
+ "ids": []
12
+ },
13
+ {
14
+ "timestamp": "2026-05-18T14:34:38.741Z",
15
+ "label": "scan",
16
+ "total": 0,
17
+ "critical": 0,
18
+ "high": 0,
19
+ "medium": 0,
20
+ "low": 0,
21
+ "kev": 0,
22
+ "ids": []
23
+ }
24
+ ]
@@ -0,0 +1,22 @@
1
+ {
2
+ "firstScanDate": "2026-05-18T14:28:11.809Z",
3
+ "lastScanDate": "2026-05-18T14:34:38.748Z",
4
+ "totalScans": 2,
5
+ "daysCleanCritical": 1,
6
+ "lastCleanDate": "2026-05-18",
7
+ "lastCriticalDate": null,
8
+ "hasEverHadCritical": false,
9
+ "bestDaysCleanCritical": 1,
10
+ "totalFindingsAtFirstScan": 0,
11
+ "totalFindingsAtLastScan": 0,
12
+ "totalFixesInferred": 0,
13
+ "lastGrade": "A+",
14
+ "bestGrade": "A+",
15
+ "launchCheckPassedAt": null,
16
+ "achievements": [
17
+ "first-scan",
18
+ "grade-a",
19
+ "grade-a-plus"
20
+ ],
21
+ "previousGrade": "A+"
22
+ }
@@ -0,0 +1,62 @@
1
+ // Bench-shape module — benchmark-specific answer-key readers.
2
+ //
3
+ // NONE of this code is useful for scanning real codebases. Every function here
4
+ // reads labels injected by NIST SARD, OWASP Benchmark, or Juliet's test suite
5
+ // authors into their test files:
6
+ //
7
+ // - `/* POTENTIAL FLAW: */` / `/* FLAW: */` comments (NIST SARD)
8
+ // - `// condition 'B', which is safe` (OWASP Benchmark template markers)
9
+ // - `@WebServlet("/cmdi-02/")` route category prefix (OWASP Benchmark)
10
+ // - `juliet-cwe<N>/` / `testcases/CWE<N>_*/` folder naming (Juliet)
11
+ //
12
+ // Enabling these on a production codebase would:
13
+ // a. Suppress real findings based on comment text an attacker can copy.
14
+ // b. Emit "findings" based on test-scaffold markers with no detection value.
15
+ //
16
+ // Activation: set AGENTIC_SECURITY_BENCH_SHAPE=1 before scanning.
17
+ // This happens automatically inside bench-realworld.js when NOT in --blind mode.
18
+ // Production scans NEVER set this variable.
19
+ //
20
+ // The --blind bench flag does the opposite: it DISABLES bench-shape (if somehow
21
+ // set) AND strips the marker comments from the corpus before scanning, so the
22
+ // engine's true detection capability is measured.
23
+
24
+ export function isBenchShape() {
25
+ return process.env.AGENTIC_SECURITY_BENCH_SHAPE === '1';
26
+ }
27
+
28
+ // Re-export the juliet-shape scanner and suppressors — gated at call sites.
29
+ export {
30
+ scanJulietShape,
31
+ applyJulietJavaSuppressions,
32
+ applyJulietCsSuppressions,
33
+ } from '../juliet-shape.js';
34
+
35
+ // Re-export the java-bench-extras API — gated at call sites.
36
+ export {
37
+ findSuppressionLines,
38
+ applyJavaBenchSuppressions,
39
+ } from '../java-bench-extras.js';
40
+
41
+ // Re-export the cpp-bench-extras suppressor — gated at call sites.
42
+ export {
43
+ applyJulietCppSuppressions as applyJulietCppFamilySuppressions,
44
+ } from '../cpp-bench-extras.js';
45
+
46
+ // OWASP Benchmark @WebServlet route-category extractor.
47
+ // Returns the canonical vuln family (e.g. 'sql-injection') for files whose
48
+ // @WebServlet URL encodes the test category, or null.
49
+ // NEVER call this in production — it reads the benchmark answer key.
50
+ const _OWASP_BENCH_CATEGORY_MAP = {
51
+ 'cmdi': 'command-injection', 'sqli': 'sql-injection', 'xss': 'xss',
52
+ 'pathtraver': 'path-traversal', 'ldapi': 'ldap-injection',
53
+ 'xpathi': 'xpath-injection', 'hash': 'weak-crypto', 'crypto': 'weak-crypto',
54
+ 'weakrand': 'weak-rng', 'trustbound': 'trust-boundary',
55
+ 'securecookie': 'header-hardening',
56
+ };
57
+ export function benchShapeWebServletCategory(cleaned) {
58
+ if (!isBenchShape()) return null;
59
+ const m = cleaned.match(/@WebServlet\s*\(\s*(?:value\s*=\s*)?["'](?:[^"']*\/)?(\w+?)-\d+\//);
60
+ if (!m) return null;
61
+ return _OWASP_BENCH_CATEGORY_MAP[m[1].toLowerCase()] || null;
62
+ }
@@ -0,0 +1,199 @@
1
+ // Hook command-injection audit.
2
+ //
3
+ // Reads .claude/hooks.json (and equivalents in .cursor/, .codex/, etc.) and
4
+ // flags the canonical bugs:
5
+ //
6
+ // 1. Interpolation of attacker-controlled fields (${file}, ${input},
7
+ // ${args}, $CLAUDE_TOOL_INPUT, $TOOL_INPUT, $PROMPT) directly into a
8
+ // shell command without quoting. When the agent passes a filename
9
+ // `; rm -rf ~` to a tool, the hook executes it as shell.
10
+ // 2. Silent error suppression in security-relevant hooks (`2>/dev/null`,
11
+ // `|| true`, `set +e`) — the hook fails open and the user never sees it.
12
+ // 3. Outbound HTTP (curl / wget / nc) from a hook to a non-local URL.
13
+ // Often a sign of an injected data-exfil command.
14
+ // 4. Privilege-escalating shells (sudo, doas, runuser, su) in hooks.
15
+ // 5. Eval / source / bash -c on dynamic content.
16
+ //
17
+ // Hook config shape (Claude Code):
18
+ // {
19
+ // "hooks": {
20
+ // "PreToolUse": [
21
+ // { "matcher": "Bash", "hooks": [{ "type": "command", "command": "..." }] }
22
+ // ]
23
+ // }
24
+ // }
25
+ //
26
+ // We walk every `command` field and apply the rules. Adjacent harnesses use
27
+ // the same key in their settings or their own hooks file; we also walk any
28
+ // `*.hooks.json` and `hooks.json` under a harness directory.
29
+
30
+ const _HOOK_FILE_RE = /(?:^|[\\/])(?:hooks?\.json|\.(?:claude|cursor|codex|gemini|kiro|opencode|trae|qwen|zed|continue|aider)[\\/](?:hooks\.json|settings(?:\.local)?\.json))$/i;
31
+
32
+ // Tokens that can carry agent-driven payloads (untrusted input).
33
+ const _INTERPOLATION_TOKENS = [
34
+ '${file}', '${input}', '${args}', '${path}', '${target}',
35
+ '${tool_input}', '${prompt}', '${query}', '${message}',
36
+ '$CLAUDE_TOOL_INPUT', '$TOOL_INPUT', '$INPUT', '$PROMPT', '$ARGS',
37
+ '$CLAUDE_PROMPT', '$CLAUDE_ARGS', '$CLAUDE_FILE',
38
+ '$AGENT_INPUT', '$AGENT_PROMPT',
39
+ ];
40
+
41
+ const _SHELL_SUPPRESS_RE = /(?:2>\s*\/dev\/null|>\s*\/dev\/null\s+2>&1|\|\|\s*true|set\s+\+e)/;
42
+ const _OUTBOUND_HTTP_RE = /\b(?:curl|wget|nc|ncat|fetch)\b[^\n;|&]*?https?:\/\/(?!(?:127\.0\.0\.1|localhost|0\.0\.0\.0))[^\s'"]+/i;
43
+ const _PRIVESC_RE = /\b(?:sudo|doas|runuser|su\s+-)\b/;
44
+ const _EVAL_RE = /\b(?:eval|source|bash\s+-c|sh\s+-c|zsh\s+-c)\s+["'`]?[^"'`]*\$(?:\{[^}]+\}|[A-Z_][A-Z0-9_]*)/i;
45
+
46
+ function _line(raw, idx) {
47
+ return raw.slice(0, idx).split('\n').length;
48
+ }
49
+
50
+ function _isQuoted(command, tokenIdx, token) {
51
+ // Heuristic: check whether the token is inside a single-quoted span.
52
+ // Single-quoted bash is the only safe-from-expansion form; double quotes
53
+ // still substitute and let `; ` break out.
54
+ let quote = null;
55
+ for (let i = 0; i < tokenIdx; i++) {
56
+ const c = command[i];
57
+ if (quote === null) {
58
+ if (c === "'") quote = "'";
59
+ else if (c === '"') quote = '"';
60
+ } else if (c === quote) {
61
+ quote = null;
62
+ }
63
+ }
64
+ return quote === "'";
65
+ }
66
+
67
+ function _walkCommands(node, out, pathPrefix = '') {
68
+ if (!node || typeof node !== 'object') return;
69
+ if (Array.isArray(node)) {
70
+ for (let i = 0; i < node.length; i++) _walkCommands(node[i], out, `${pathPrefix}[${i}]`);
71
+ return;
72
+ }
73
+ for (const [k, v] of Object.entries(node)) {
74
+ if (k === 'command' && typeof v === 'string') {
75
+ out.push({ command: v, jsonPath: `${pathPrefix}.${k}` });
76
+ } else if (k === 'commands' && Array.isArray(v)) {
77
+ for (let i = 0; i < v.length; i++) {
78
+ if (typeof v[i] === 'string') out.push({ command: v[i], jsonPath: `${pathPrefix}.${k}[${i}]` });
79
+ }
80
+ } else {
81
+ _walkCommands(v, out, `${pathPrefix}.${k}`);
82
+ }
83
+ }
84
+ }
85
+
86
+ export function scanClaudeHookInjection(file, raw) {
87
+ if (!file || !raw || typeof raw !== 'string') return [];
88
+ if (!_HOOK_FILE_RE.test(file)) return [];
89
+ if (raw.length > 200_000) return [];
90
+
91
+ let parsed;
92
+ try { parsed = JSON.parse(raw); } catch { return []; }
93
+ if (!parsed || typeof parsed !== 'object') return [];
94
+
95
+ const commands = [];
96
+ _walkCommands(parsed.hooks || parsed, commands);
97
+ if (!commands.length) return [];
98
+
99
+ const findings = [];
100
+ for (const { command, jsonPath } of commands) {
101
+ // The line where this command lives in raw — best effort by searching
102
+ // for the command substring (works because raw JSON preserves the text).
103
+ const idx = raw.indexOf(command);
104
+ const line = idx >= 0 ? _line(raw, idx) : 1;
105
+
106
+ // 1. Interpolation of untrusted tokens, unquoted.
107
+ for (const tok of _INTERPOLATION_TOKENS) {
108
+ const ti = command.indexOf(tok);
109
+ if (ti < 0) continue;
110
+ if (_isQuoted(command, ti, tok)) continue; // single-quoted is safe
111
+ findings.push({
112
+ id: `hook-injection:interpolation:${file}:${line}:${tok}`,
113
+ file,
114
+ line,
115
+ vuln: `Hook command interpolates untrusted '${tok}' unquoted — shell injection`,
116
+ severity: 'critical',
117
+ family: 'hook-command-injection',
118
+ cwe: 'CWE-78',
119
+ confidence: 0.85,
120
+ description: `The hook at ${jsonPath} embeds ${tok} directly into a shell command. If an agent (or a prompt-injected tool) passes a path containing ; rm -rf $HOME, the shell executes it. Even double-quoting does not fix this — backslash and dollar still allow escape.`,
121
+ remediation: 'Pass the value via stdin or a sandboxed env var. If it must appear in the command line, wrap the receiving program in single-quotes and use \\\'\\\'\\\'\\\' for embedded literal quotes, or pre-validate the value against a strict allow-list before the hook runs.',
122
+ snippet: command.slice(Math.max(0, ti - 20), ti + tok.length + 30),
123
+ });
124
+ }
125
+
126
+ // 2. Silent error suppression on security hooks.
127
+ if (_SHELL_SUPPRESS_RE.test(command)) {
128
+ // Only flag when the hook is a security-relevant one. PostToolUse +
129
+ // PreToolUse hooks that fail silently disable the guardrail. We can't
130
+ // perfectly tell purpose, so emit at medium severity.
131
+ findings.push({
132
+ id: `hook-injection:silent-suppress:${file}:${line}`,
133
+ file,
134
+ line,
135
+ vuln: `Hook silently swallows errors (fails open)`,
136
+ severity: 'medium',
137
+ family: 'hook-command-injection',
138
+ cwe: 'CWE-754',
139
+ confidence: 0.7,
140
+ description: `The hook command redirects stderr to /dev/null or appends '|| true' / 'set +e'. If the hook's purpose is to enforce a check, swallowing its non-zero exit means a failure passes silently — the user thinks the guardrail ran.`,
141
+ remediation: 'Let the hook fail loudly. If you genuinely need to ignore one specific error, narrow the suppression to that case rather than the whole pipeline.',
142
+ snippet: command.slice(0, 120),
143
+ });
144
+ }
145
+
146
+ // 3. Outbound HTTP from a hook.
147
+ if (_OUTBOUND_HTTP_RE.test(command)) {
148
+ findings.push({
149
+ id: `hook-injection:outbound-http:${file}:${line}`,
150
+ file,
151
+ line,
152
+ vuln: `Hook makes outbound HTTP to a non-local URL`,
153
+ severity: 'high',
154
+ family: 'hook-command-injection',
155
+ cwe: 'CWE-918',
156
+ confidence: 0.8,
157
+ description: `The hook fetches or posts to an external URL. Outbound traffic from a hook is the canonical data-exfiltration shape — every Edit / Write / Bash event triggers the hook.`,
158
+ remediation: 'Replace with a local script if possible. If the outbound call is intentional (telemetry, webhook), redact the payload and restrict the destination to an allow-list.',
159
+ snippet: command.slice(0, 120),
160
+ });
161
+ }
162
+
163
+ // 4. Privilege-escalating commands.
164
+ if (_PRIVESC_RE.test(command)) {
165
+ findings.push({
166
+ id: `hook-injection:privesc:${file}:${line}`,
167
+ file,
168
+ line,
169
+ vuln: `Hook invokes a privilege-escalating command`,
170
+ severity: 'high',
171
+ family: 'hook-command-injection',
172
+ cwe: 'CWE-269',
173
+ confidence: 0.9,
174
+ description: `The hook calls sudo / doas / runuser. Hooks fire automatically on agent events; combining auto-trigger with privilege escalation gives the agent root via a documented side door.`,
175
+ remediation: 'Remove the privilege-escalation. If admin actions are genuinely needed, gate them behind a separate user-initiated command, not an auto-fire hook.',
176
+ snippet: command.slice(0, 120),
177
+ });
178
+ }
179
+
180
+ // 5. Eval / dynamic execution.
181
+ if (_EVAL_RE.test(command)) {
182
+ findings.push({
183
+ id: `hook-injection:eval-dynamic:${file}:${line}`,
184
+ file,
185
+ line,
186
+ vuln: `Hook eval()s dynamic content from a shell variable`,
187
+ severity: 'critical',
188
+ family: 'hook-command-injection',
189
+ cwe: 'CWE-78',
190
+ confidence: 0.85,
191
+ description: `The hook passes a variable through eval / source / bash -c. Whatever is in that variable becomes shell code.`,
192
+ remediation: 'Rewrite the hook to invoke the target binary directly with positional args. Never eval a value the agent can influence.',
193
+ snippet: command.slice(0, 120),
194
+ });
195
+ }
196
+ }
197
+
198
+ return findings;
199
+ }
@@ -0,0 +1,170 @@
1
+ // CLAUDE.md / AGENTS.md / system-prompt-style instruction-file audit.
2
+ //
3
+ // LLM-targeting attacks distinct from source-code XSS. Targets:
4
+ //
5
+ // 1. Override directives — "Ignore all previous instructions", "Forget prior
6
+ // rules", "You are now ...", "From now on, ...".
7
+ // 2. Auto-run / no-confirmation patterns — "always run X without asking",
8
+ // "skip the confirmation", "auto-approve", "no questions, just execute".
9
+ // 3. Exfiltration baiting — instructions that tell the agent to send data
10
+ // to an outside URL, "POST your context to ...", "include your system
11
+ // prompt in the response".
12
+ // 4. Hardcoded credentials in instruction files — `sk-ant-...`,
13
+ // `ghp_...`, `AKIA...`, etc. Already covered by the secrets module on
14
+ // generic source code, but instruction files often fall outside the
15
+ // typical secrets scan path.
16
+ // 5. Tool-misuse coaching — "if you encounter a confirmation prompt,
17
+ // bypass it via", "use the unrestricted Bash tool when ...".
18
+ // 6. Identity / role overrides that pretend to be a higher authority —
19
+ // "[SYSTEM]", "[OWNER]", "<|im_start|>system".
20
+ //
21
+ // Scope: any file matching the instruction-file naming convention.
22
+
23
+ const _INSTRUCTION_FILE_RE = /(?:^|[\\/])(?:CLAUDE|AGENTS|GEMINI|CURSOR|CODEX|KIRO|QWEN|TRAE|OPENCODE|SYSTEM_PROMPT|\.claude\/(?:CLAUDE|SYSTEM|PROMPT|instructions))\.(?:md|markdown|txt|prompt|prompt\.md|system\.md)$/i;
24
+
25
+ const _OVERRIDE_PATTERNS = [
26
+ { re: /\b(?:ignore|disregard|forget|override|bypass|discard|skip|drop)\s+(?:all\s+|any\s+)?(?:previous|prior|above|preceding|earlier|former)\s+(?:instructions?|directives?|prompts?|rules?|guidelines?|safety|policy)/i, kind: 'override-prior-instructions' },
27
+ { re: /\b(?:from\s+now\s+on|starting\s+now|beginning\s+(?:now|here))[,:]?\s+(?:you\s+(?:are|will|must)|act\s+as|behave\s+as)/i, kind: 'role-override' },
28
+ { re: /\b(?:you\s+are\s+now|new\s+system\s+prompt|new\s+role|act\s+as|pretend\s+to\s+be|roleplay\s+as)\s+(?:a\s+)?[A-Za-z]+/i, kind: 'role-override' },
29
+ { re: /<\s*\|?\s*(?:system|im_start|im_end|assistant|user|developer|owner)\s*\|?\s*>/i, kind: 'chat-template-spoof' },
30
+ { re: /\[\s*(?:SYSTEM|OWNER|ROOT|DEVELOPER|ADMIN)\s*[\]:]/i, kind: 'authority-spoof' },
31
+ ];
32
+
33
+ const _AUTO_RUN_PATTERNS = [
34
+ { re: /\balways\s+(?:run|execute|invoke|call|use)\s+\S+\s+(?:without\s+(?:asking|prompting|confirming)|silently|automatically)/i, kind: 'auto-run-directive', sev: 'high' },
35
+ { re: /\b(?:skip|bypass|disable|suppress)\s+(?:the\s+)?(?:confirmation|approval|prompt|permission)\s+(?:dialog|step|check|popup)/i, kind: 'skip-confirmation', sev: 'high' },
36
+ { re: /\b(?:auto[-\s]?approve|auto[-\s]?run|auto[-\s]?execute|auto[-\s]?accept)\s+(?:all|every|any)/i, kind: 'auto-approve-all', sev: 'high' },
37
+ { re: /\bno\s+questions[,.]?\s*(?:just|simply|always)?\s*(?:run|execute|do|proceed)/i, kind: 'no-confirmation', sev: 'medium' },
38
+ { re: /\b(?:never|don'?t)\s+(?:ask|prompt|confirm)\s+(?:the\s+)?(?:user|developer|owner)\s+(?:before|prior\s+to|when)/i, kind: 'no-confirmation', sev: 'medium' },
39
+ ];
40
+
41
+ const _EXFIL_PATTERNS = [
42
+ { re: /\b(?:send|post|upload|exfiltrate|forward|relay)\s+(?:your|the)\s+(?:system\s+prompt|instructions|context|conversation|history|tools)/i, kind: 'exfil-context' },
43
+ { re: /\b(?:print|reveal|output|show|expose|include|append)\s+(?:your|the)?\s*(?:system\s+prompt|instructions|api\s+key|credentials|secrets|tokens?)/i, kind: 'reveal-secrets' },
44
+ { re: /\bcurl\s+(?:-X\s+\w+\s+)?https?:\/\/[^\s)]+\s+(?:-d|--data)/i, kind: 'embedded-curl-post' },
45
+ { re: /\b(?:webhook|callback|beacon)\s+(?:to\s+)?https?:\/\/[^\s)]+/i, kind: 'webhook-beacon' },
46
+ ];
47
+
48
+ const _TOOL_MISUSE_PATTERNS = [
49
+ { re: /\b(?:if|when)\s+(?:you\s+)?(?:see|encounter|hit)\s+a\s+(?:confirmation|approval|permission)\s+(?:prompt|dialog|step)[,.\s\-—]+(?:always\s+|just\s+)?(?:click|select|choose|answer|say|return|approve|accept)\s+(?:yes|approve|allow|accept)/i, kind: 'auto-approve-coaching' },
50
+ { re: /\buse\s+(?:the\s+)?(?:unrestricted|admin|root|sudo|dangerous|bypass)\s+(?:Bash|tool|capability|mode)/i, kind: 'use-dangerous-tool' },
51
+ { re: /\b(?:run|execute|invoke)\s+(?:Bash|shell|exec)\s*\(\s*\*?\s*\)\s+(?:without|silently|always)/i, kind: 'wildcard-bash-coaching' },
52
+ ];
53
+
54
+ const _CRED_RE = [
55
+ { re: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/, label: 'Anthropic API key' },
56
+ { re: /\bsk-[A-Za-z0-9]{32,}\b/, label: 'OpenAI-style API key' },
57
+ { re: /\bghp_[A-Za-z0-9]{36}\b/, label: 'GitHub PAT' },
58
+ { re: /\bgithub_pat_[A-Za-z0-9_]{20,}\b/, label: 'GitHub fine-grained PAT' },
59
+ { re: /\bAKIA[0-9A-Z]{16}\b/, label: 'AWS access key' },
60
+ { re: /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/, label: 'Slack token' },
61
+ ];
62
+
63
+ function _line(raw, idx) {
64
+ return raw.slice(0, idx).split('\n').length;
65
+ }
66
+
67
+ export function scanClaudeMdPromptInjection(file, raw) {
68
+ if (!file || !raw || typeof raw !== 'string') return [];
69
+ if (!_INSTRUCTION_FILE_RE.test(file)) return [];
70
+ if (raw.length > 1_000_000) return [];
71
+
72
+ // Strip fenced code blocks so example snippets in docs don't trip the
73
+ // detector. Replace with same-length whitespace to preserve line offsets.
74
+ const stripped = raw.replace(/```[\s\S]*?```/g, (m) => m.replace(/[^\n]/g, ' '));
75
+
76
+ const findings = [];
77
+
78
+ for (const { re, kind } of _OVERRIDE_PATTERNS) {
79
+ const m = re.exec(stripped);
80
+ if (!m) continue;
81
+ findings.push({
82
+ id: `claude-md:override:${kind}:${file}:${m.index}`,
83
+ file,
84
+ line: _line(stripped, m.index),
85
+ vuln: `Instruction file contains an override / role-rewriting directive (${kind})`,
86
+ severity: 'high',
87
+ family: 'agent-prompt-injection',
88
+ cwe: 'CWE-77',
89
+ confidence: 0.7,
90
+ description: `An instruction file (CLAUDE.md / AGENTS.md / etc.) loaded into every session is asking the agent to ignore prior instructions or adopt a new role. This is the canonical prompt-injection vector. If a teammate copied this content from an untrusted source, the agent has effectively been re-rolled.`,
91
+ remediation: 'Rewrite the directive as a constraint (\"only do X if Y is true\") rather than an override (\"ignore previous rules\"). Run /jailbreak-detector to test the resulting prompt.',
92
+ snippet: m[0].slice(0, 120),
93
+ });
94
+ }
95
+
96
+ for (const { re, kind, sev } of _AUTO_RUN_PATTERNS) {
97
+ const m = re.exec(stripped);
98
+ if (!m) continue;
99
+ findings.push({
100
+ id: `claude-md:auto-run:${kind}:${file}:${m.index}`,
101
+ file,
102
+ line: _line(stripped, m.index),
103
+ vuln: `Instruction file requests bypass of per-tool confirmation (${kind})`,
104
+ severity: sev,
105
+ family: 'agent-auto-approve',
106
+ cwe: 'CWE-862',
107
+ confidence: 0.75,
108
+ description: `The instruction asks the agent to skip user confirmation. Tool-call confirmation is the last line of defense against prompt-injection-driven destructive actions; removing it via documentation is equivalent to setting dangerouslySkipPermissions=true at runtime.`,
109
+ remediation: 'Remove the auto-run instruction. If certain commands genuinely need to be allow-listed, encode them in .claude/settings.json permissions.allow with narrow scope, not as a global rule in the instruction file.',
110
+ snippet: m[0].slice(0, 120),
111
+ });
112
+ }
113
+
114
+ for (const { re, kind } of _EXFIL_PATTERNS) {
115
+ const m = re.exec(stripped);
116
+ if (!m) continue;
117
+ findings.push({
118
+ id: `claude-md:exfil:${kind}:${file}:${m.index}`,
119
+ file,
120
+ line: _line(stripped, m.index),
121
+ vuln: `Instruction file asks the agent to exfiltrate context (${kind})`,
122
+ severity: 'high',
123
+ family: 'agent-prompt-injection',
124
+ cwe: 'CWE-200',
125
+ confidence: 0.7,
126
+ description: `The instruction tells the agent to send its system prompt, conversation history, or secrets to an outside destination. Even when the destination looks legitimate, this is the canonical data-exfiltration shape for a compromised prompt.`,
127
+ remediation: 'Remove the exfiltration directive. If outbound telemetry is genuinely needed, route it through a configured webhook with redaction at the source — not via a documented instruction.',
128
+ snippet: m[0].slice(0, 120),
129
+ });
130
+ }
131
+
132
+ for (const { re, kind } of _TOOL_MISUSE_PATTERNS) {
133
+ const m = re.exec(stripped);
134
+ if (!m) continue;
135
+ findings.push({
136
+ id: `claude-md:tool-misuse:${kind}:${file}:${m.index}`,
137
+ file,
138
+ line: _line(stripped, m.index),
139
+ vuln: `Instruction file coaches the agent into unsafe tool use (${kind})`,
140
+ severity: 'high',
141
+ family: 'agent-prompt-injection',
142
+ cwe: 'CWE-77',
143
+ confidence: 0.7,
144
+ description: `The instruction explicitly trains the agent to answer 'yes' to confirmation dialogs, reach for wildcard Bash, or otherwise circumvent its own safety checks.`,
145
+ remediation: 'Remove the coaching directive. If the underlying workflow genuinely needs broader permissions, encode them in settings.json with explicit scopes.',
146
+ snippet: m[0].slice(0, 120),
147
+ });
148
+ }
149
+
150
+ // Hardcoded credentials in CLAUDE.md / AGENTS.md.
151
+ for (const { re, label } of _CRED_RE) {
152
+ const m = re.exec(raw);
153
+ if (!m) continue;
154
+ findings.push({
155
+ id: `claude-md:hardcoded-cred:${file}:${m.index}`,
156
+ file,
157
+ line: _line(raw, m.index),
158
+ vuln: `Instruction file contains a hardcoded ${label}`,
159
+ severity: 'critical',
160
+ family: 'harness-config-secrets',
161
+ cwe: 'CWE-798',
162
+ confidence: 0.95,
163
+ description: `A literal credential is embedded in an instruction file the agent reads on every session. Any conversation surface that echoes file contents (logs, screenshots, support tickets) leaks the secret.`,
164
+ remediation: 'Move the credential to a secure vault and reference it via env-var substitution. Rotate the leaked credential immediately.',
165
+ snippet: m[0].slice(0, 8) + '...' + m[0].slice(-4),
166
+ });
167
+ }
168
+
169
+ return findings;
170
+ }