@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,80 @@
1
+ #!/usr/bin/env node
2
+ // CLI front-end for the LLM-validator consistency harness.
3
+ //
4
+ // Reads .agentic-security/last-scan.json from the project root, picks the
5
+ // top-N findings with precise file:line locations (validator preflight
6
+ // requires them), and runs N trials of the validator on the same finding
7
+ // set. Reports pass^N (unanimous-verdict rate) and per-finding flap detail.
8
+ //
9
+ // The validator endpoint is configured via the usual env vars:
10
+ // AGENTIC_SECURITY_LLM_VALIDATE=1
11
+ // AGENTIC_SECURITY_LLM_ENDPOINT=https://...
12
+ // AGENTIC_SECURITY_LLM_API_KEY=...
13
+ // AGENTIC_SECURITY_LLM_MODEL=...
14
+ //
15
+ // When the validator is off (env unset), every verdict will be 'unvalidated'
16
+ // and pass^N is trivially 100%. That's an honest signal; deploy with the
17
+ // validator on if you care about its behavior.
18
+ //
19
+ // Usage:
20
+ // agentic-security-consistency # uses last-scan, 5 trials, 5 findings
21
+ // agentic-security-consistency --trials 10
22
+ // agentic-security-consistency --top 3
23
+ // agentic-security-consistency --json
24
+ 'use strict';
25
+ import * as fs from 'node:fs';
26
+ import * as path from 'node:path';
27
+ import { measureConsistency, summarize } from '../src/llm-validator/consistency.js';
28
+
29
+ function args() {
30
+ const a = process.argv.slice(2);
31
+ const out = { trials: 5, top: 5, json: false, root: process.cwd() };
32
+ for (let i = 0; i < a.length; i++) {
33
+ if (a[i] === '--trials') out.trials = parseInt(a[++i], 10);
34
+ else if (a[i] === '--top') out.top = parseInt(a[++i], 10);
35
+ else if (a[i] === '--json') out.json = true;
36
+ else if (a[i] === '--root') out.root = a[++i];
37
+ }
38
+ return out;
39
+ }
40
+
41
+ async function main() {
42
+ const opts = args();
43
+ const scanFile = path.join(opts.root, '.agentic-security', 'last-scan.json');
44
+ if (!fs.existsSync(scanFile)) {
45
+ console.error(`no last-scan.json at ${scanFile} — run a scan first`);
46
+ process.exit(2);
47
+ }
48
+ let scan;
49
+ try { scan = JSON.parse(fs.readFileSync(scanFile, 'utf8')); }
50
+ catch (e) { console.error(`failed to parse last-scan.json: ${e.message}`); process.exit(2); }
51
+ // Pick findings the validator can actually grade: must have precise file+line.
52
+ const candidates = (scan.findings || [])
53
+ .filter(f => f && typeof f.file === 'string' && f.file.length > 0 &&
54
+ typeof f.line === 'number' && f.line > 0)
55
+ .slice(0, opts.top);
56
+ if (!candidates.length) {
57
+ console.error('no findings with precise locations in last-scan.json');
58
+ process.exit(2);
59
+ }
60
+ // Build fileContents map from scan.fc if present, otherwise read from disk.
61
+ const fileContents = (scan.fc && typeof scan.fc === 'object') ? scan.fc : {};
62
+ for (const f of candidates) {
63
+ if (fileContents[f.file]) continue;
64
+ try {
65
+ const fp = path.join(opts.root, f.file);
66
+ if (fs.existsSync(fp)) fileContents[f.file] = fs.readFileSync(fp, 'utf8');
67
+ } catch { /* skip */ }
68
+ }
69
+ const r = await measureConsistency({
70
+ findings: candidates, fileContents,
71
+ scanRoot: opts.root, trials: opts.trials,
72
+ });
73
+ if (opts.json) {
74
+ console.log(JSON.stringify(r, null, 2));
75
+ return;
76
+ }
77
+ console.log(summarize(r));
78
+ }
79
+
80
+ main().catch(e => { console.error(e); process.exit(1); });
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+ // FR-SDLC-10 — Differential scanner CLI.
3
+ //
4
+ // Run two versions of the scanner against the same target and emit the
5
+ // delta. Use cases:
6
+ // 1. PR-time regression detection — catch when an upgrade of the scanner
7
+ // itself loses or adds findings on a stable codebase.
8
+ // 2. Migration confidence — let a customer dry-run a scanner upgrade
9
+ // before bumping their pinned version.
10
+ //
11
+ // Usage:
12
+ // agentic-security-diff --baseline ./dist/agentic-security.mjs \
13
+ // --candidate ./dist/agentic-security.mjs.next \
14
+ // [--root .]
15
+ //
16
+ // Both `--baseline` and `--candidate` paths must point to runnable scanner
17
+ // bundles. The CLI invokes each via child_process with `--format json` and
18
+ // computes the diff on the resulting findings list (keyed by `stableId`
19
+ // when present, else by `(file, line, family)`).
20
+
21
+ import { spawnSync } from 'node:child_process';
22
+ import * as path from 'node:path';
23
+ import * as fs from 'node:fs';
24
+
25
+ function parseArgs(argv) {
26
+ const opts = { root: '.', baseline: null, candidate: null, format: 'cli' };
27
+ for (let i = 2; i < argv.length; i++) {
28
+ const a = argv[i];
29
+ if (a === '--baseline') opts.baseline = argv[++i];
30
+ else if (a === '--candidate') opts.candidate = argv[++i];
31
+ else if (a === '--root') opts.root = argv[++i];
32
+ else if (a === '--format') opts.format = argv[++i];
33
+ else if (a === '--help' || a === '-h') opts.help = true;
34
+ }
35
+ return opts;
36
+ }
37
+
38
+ function runScan(binPath, root) {
39
+ if (!fs.existsSync(binPath)) {
40
+ return { error: `binary not found: ${binPath}`, findings: [] };
41
+ }
42
+ const res = spawnSync(process.execPath, [binPath, 'scan', root, '--format', 'json'], {
43
+ encoding: 'utf8',
44
+ maxBuffer: 256 * 1024 * 1024,
45
+ stdio: ['ignore', 'pipe', 'pipe'],
46
+ });
47
+ if (res.status !== 0 && !res.stdout) {
48
+ return { error: `scanner exited ${res.status}: ${(res.stderr || '').slice(0, 200)}`, findings: [] };
49
+ }
50
+ try {
51
+ const data = JSON.parse(res.stdout);
52
+ const findings = Array.isArray(data) ? data : (data.findings || []);
53
+ return { findings };
54
+ } catch (e) {
55
+ return { error: `failed to parse JSON: ${e.message}`, findings: [] };
56
+ }
57
+ }
58
+
59
+ function keyOf(f) {
60
+ if (f.stableId) return `sid:${f.stableId}`;
61
+ return `pos:${f.file}:${f.line}:${f.family || f.vuln || '?'}`;
62
+ }
63
+
64
+ function diff(baseline, candidate) {
65
+ const byKey = (arr) => {
66
+ const m = new Map();
67
+ for (const f of arr) m.set(keyOf(f), f);
68
+ return m;
69
+ };
70
+ const a = byKey(baseline);
71
+ const b = byKey(candidate);
72
+ const added = [], removed = [], changed = [];
73
+ for (const [k, f] of b) {
74
+ if (!a.has(k)) added.push(f);
75
+ else {
76
+ const prev = a.get(k);
77
+ if (prev.severity !== f.severity || prev.vuln !== f.vuln) changed.push({ before: prev, after: f });
78
+ }
79
+ }
80
+ for (const [k, f] of a) if (!b.has(k)) removed.push(f);
81
+ return { added, removed, changed };
82
+ }
83
+
84
+ function summarize(d) {
85
+ const lines = [];
86
+ lines.push('# Differential scan report');
87
+ lines.push('');
88
+ lines.push(`Added: ${d.added.length}`);
89
+ lines.push(`Removed: ${d.removed.length}`);
90
+ lines.push(`Changed: ${d.changed.length}`);
91
+ lines.push('');
92
+ if (d.added.length) {
93
+ lines.push('## Added (candidate found, baseline did not)');
94
+ for (const f of d.added.slice(0, 25)) lines.push(` + [${f.severity}] ${f.vuln || ''} at ${f.file}:${f.line}`);
95
+ if (d.added.length > 25) lines.push(` + ... ${d.added.length - 25} more`);
96
+ lines.push('');
97
+ }
98
+ if (d.removed.length) {
99
+ lines.push('## Removed (baseline found, candidate did not)');
100
+ for (const f of d.removed.slice(0, 25)) lines.push(` - [${f.severity}] ${f.vuln || ''} at ${f.file}:${f.line}`);
101
+ if (d.removed.length > 25) lines.push(` - ... ${d.removed.length - 25} more`);
102
+ lines.push('');
103
+ }
104
+ if (d.changed.length) {
105
+ lines.push('## Changed (same finding, different severity or wording)');
106
+ for (const c of d.changed.slice(0, 15)) {
107
+ lines.push(` ~ [${c.before.severity}→${c.after.severity}] ${c.after.file}:${c.after.line}`);
108
+ }
109
+ lines.push('');
110
+ }
111
+ return lines.join('\n');
112
+ }
113
+
114
+ function main() {
115
+ const opts = parseArgs(process.argv);
116
+ if (opts.help || !opts.baseline || !opts.candidate) {
117
+ console.log('Usage: agentic-security-diff --baseline <bin> --candidate <bin> [--root .] [--format cli|json]');
118
+ process.exit(opts.help ? 0 : 1);
119
+ }
120
+ const root = path.resolve(opts.root);
121
+ const baseline = runScan(opts.baseline, root);
122
+ const candidate = runScan(opts.candidate, root);
123
+ if (baseline.error) { console.error('baseline:', baseline.error); process.exit(2); }
124
+ if (candidate.error) { console.error('candidate:', candidate.error); process.exit(2); }
125
+ const d = diff(baseline.findings, candidate.findings);
126
+ if (opts.format === 'json') {
127
+ process.stdout.write(JSON.stringify(d, null, 2));
128
+ } else {
129
+ process.stdout.write(summarize(d));
130
+ }
131
+ // Exit 0 if no delta, 1 if delta, 2 if errors (already exited above).
132
+ const hasDelta = d.added.length || d.removed.length || d.changed.length;
133
+ process.exit(hasDelta ? 1 : 0);
134
+ }
135
+
136
+ main();
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ // agentic-security LSP server — stdio entry point.
3
+ //
4
+ // Speaks the Language Server Protocol (vscode-jsonrpc framing) on stdin/stdout.
5
+ // Used by the JetBrains plugin (via LSP4IJ) and the Neovim plugin (via
6
+ // built-in LSP). Diagnostics emitted to publishDiagnostics on save/open.
7
+ //
8
+ // Usage (typically invoked by an editor, not directly):
9
+ // node bin/agentic-security-lsp.js
10
+ //
11
+ import { startLspServer } from '../src/lsp/server.js';
12
+ startLspServer();
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ // agentic-security MCP server — stdio entry point.
3
+ //
4
+ // Speaks JSON-RPC 2.0 over NDJSON on stdin/stdout. stderr is for logging.
5
+ //
6
+ // Usage:
7
+ // node bin/agentic-security-mcp.js [--root <path>]
8
+ //
9
+ // Session root resolution (highest precedence first):
10
+ // 1. --root <path> CLI arg
11
+ // 2. AGENTIC_SECURITY_MCP_ROOT env var
12
+ // 3. process.cwd()
13
+ //
14
+ // The session root confines every tool: paths in tool arguments must resolve
15
+ // inside it, and apply_fix refuses any finding whose file field escapes it.
16
+
17
+ import * as path from 'node:path';
18
+ import { runStdio } from '../src/mcp/stdio.js';
19
+
20
+ function _parseRoot() {
21
+ const argv = process.argv.slice(2);
22
+ for (let i = 0; i < argv.length; i++) {
23
+ if (argv[i] === '--root' && argv[i + 1]) return argv[i + 1];
24
+ if (argv[i].startsWith('--root=')) return argv[i].slice('--root='.length);
25
+ }
26
+ return process.env.AGENTIC_SECURITY_MCP_ROOT || process.cwd();
27
+ }
28
+
29
+ // Operator kill-switch (OWASP MCP09 Shadow MCP Servers): bin exits
30
+ // immediately if disabled. Tool calls would also be refused server-side,
31
+ // but exiting early prevents the process from staying resident as an
32
+ // invisible attack surface on machines where the env var is set.
33
+ if (process.env.AGENTIC_SECURITY_MCP_DISABLED === '1') {
34
+ process.stderr.write('mcp: disabled via AGENTIC_SECURITY_MCP_DISABLED=1 — exiting.\n');
35
+ process.exit(0);
36
+ }
37
+
38
+ const sessionRoot = path.resolve(_parseRoot());
39
+ process.stderr.write(`mcp: session root = ${sessionRoot}\n`);
40
+ runStdio({ sessionRoot });
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ // agentic-security-rule — CLI for signing / verifying custom rule packs.
3
+ //
4
+ // Subcommands:
5
+ // keygen Generate an Ed25519 key pair (PRIVATE KEY printed
6
+ // to stdout; handle with care).
7
+ // sign <rule-yml> Sign the rule file. Writes <rule-yml>.sig.
8
+ // Reads the private key from $AGENTIC_SECURITY_PRIVATE_KEY
9
+ // or --key <base64>.
10
+ // verify <rule-yml> Verify against the project's trusted-keys.json
11
+ // (or bundled official keys). Honors revocation.
12
+ //
13
+ // First-time setup walkthrough:
14
+ //
15
+ // 1) Generate a key pair OUTSIDE the project tree:
16
+ // mkdir -p ~/.config/agentic-security/keys
17
+ // agentic-security-rule keygen --out ~/.config/agentic-security/keys/MY_KEY.json
18
+ // (the file is written 0600. KEEP the private key SECRET — do not commit it,
19
+ // do not put it in a cloud-synced directory.)
20
+ //
21
+ // 2) Add the public key to .agentic-security/trusted-keys.json:
22
+ // {
23
+ // "keys": [
24
+ // { "id": "my-team-2026", "alg": "ed25519",
25
+ // "publicKey": "<paste publicKey from step 1>" }
26
+ // ]
27
+ // }
28
+ //
29
+ // 3) Tell the scanner to trust project-local keys (audit-logged):
30
+ // export AGENTIC_SECURITY_ALLOW_PROJECT_KEYS=1
31
+ //
32
+ // 4) Author a custom rule at .agentic-security/rules/my-rule.yml.
33
+ //
34
+ // 5) Sign it:
35
+ // export AGENTIC_SECURITY_PRIVATE_KEY="<paste privateKey from step 1>"
36
+ // agentic-security-rule sign .agentic-security/rules/my-rule.yml
37
+ //
38
+ // 6) Verify before commit:
39
+ // agentic-security-rule verify .agentic-security/rules/my-rule.yml
40
+ //
41
+ // CAUTION: the private key in step 1 is a SECRET. Anyone with it can sign
42
+ // rules that will execute in your CI. Store in a password manager / KMS,
43
+ // never in source control or shell history. Use --rotate to retire keys.
44
+
45
+ import { keygen, signRulePack, verifyRulePack, loadTrustedKeys } from '../src/posture/rule-pack-signing.js';
46
+ import * as fs from 'node:fs';
47
+ import * as path from 'node:path';
48
+
49
+ const cmd = process.argv[2];
50
+ const args = process.argv.slice(3);
51
+
52
+ function die(msg, code = 1) {
53
+ process.stderr.write(msg + '\n');
54
+ process.exit(code);
55
+ }
56
+
57
+ function pickArg(flag) {
58
+ const i = args.indexOf(flag);
59
+ return i >= 0 ? args[i + 1] : null;
60
+ }
61
+
62
+ if (cmd === 'keygen') {
63
+ // Premortem 3R3.2 / 3R-5: keygen output contains a PRIVATE KEY. Three
64
+ // safety rails:
65
+ // 1. If --out <path> is supplied AND the path resolves under the project's
66
+ // .agentic-security/ directory, REFUSE. That directory tends to be
67
+ // cloud-synced / git-checked / editor-recent. The right place for
68
+ // private keys is outside source control.
69
+ // 2. If stdout is not a TTY (redirected to a file or pipe) AND no --out
70
+ // was specified, WARN that the operator is about to write a private
71
+ // key somewhere we can't see; suggest --out so we can validate.
72
+ // 3. Operators who really mean it can pass --i-understand-private-keys
73
+ // to silence the warnings.
74
+ const outArg = pickArg('--out');
75
+ const understandFlag = args.includes('--i-understand-private-keys');
76
+ if (outArg) {
77
+ const projectAgenticDir = path.resolve(process.cwd(), '.agentic-security') + path.sep;
78
+ const absOut = path.resolve(outArg);
79
+ if (absOut.startsWith(projectAgenticDir)) {
80
+ die(
81
+ `Refusing to write a private key into ${absOut}.\n` +
82
+ ` .agentic-security/ is typically git-tracked, cloud-synced, or editor-indexed.\n` +
83
+ ` Choose a location OUTSIDE the project tree (e.g. ~/.config/agentic-security/keys/).\n` +
84
+ ` Override with --i-understand-private-keys if you really mean it.`,
85
+ 2);
86
+ }
87
+ } else if (!process.stdout.isTTY && !understandFlag) {
88
+ process.stderr.write(
89
+ 'agentic-security-rule: WARNING — stdout is being redirected, but no --out was specified.\n' +
90
+ ' This command emits a PRIVATE KEY. We cannot validate where it ends up.\n' +
91
+ ' Re-run with --out <path-outside-project> so we can check the destination,\n' +
92
+ ' or with --i-understand-private-keys to silence this warning.\n');
93
+ process.exit(3);
94
+ }
95
+ const kp = keygen();
96
+ const out = {
97
+ note: 'STORE THE privateKey SECURELY. Do not commit it to source control. Anyone with this key can sign rules that execute in your CI.',
98
+ id: `key-${new Date().toISOString().slice(0, 10)}-${Math.random().toString(36).slice(2, 6)}`,
99
+ alg: 'ed25519',
100
+ issuedAt: new Date().toISOString(),
101
+ publicKey: kp.publicKey,
102
+ privateKey: kp.privateKey,
103
+ };
104
+ const payload = JSON.stringify(out, null, 2) + '\n';
105
+ if (outArg) {
106
+ fs.writeFileSync(outArg, payload, { mode: 0o600 });
107
+ process.stderr.write(`\nagentic-security-rule: keypair written to ${outArg} (mode 0600).\n`);
108
+ } else {
109
+ process.stdout.write(payload);
110
+ }
111
+ process.stderr.write(' · Add publicKey to .agentic-security/trusted-keys.json (this IS git-trackable)\n');
112
+ process.stderr.write(' · Store privateKey in a password manager / KMS\n');
113
+ process.stderr.write(' · Set AGENTIC_SECURITY_ALLOW_PROJECT_KEYS=1 so the scanner trusts project-local keys\n');
114
+ process.exit(0);
115
+ }
116
+
117
+ if (cmd === 'sign') {
118
+ const target = args.find(a => !a.startsWith('--'));
119
+ if (!target) die('Usage: agentic-security-rule sign <rule-yml> [--key <base64>]');
120
+ if (!fs.existsSync(target)) die(`File not found: ${target}`);
121
+ const key = pickArg('--key') || process.env.AGENTIC_SECURITY_PRIVATE_KEY;
122
+ if (!key) die('No private key. Set AGENTIC_SECURITY_PRIVATE_KEY or pass --key <base64>.');
123
+ try {
124
+ signRulePack(target, key);
125
+ process.stdout.write(`Signed: ${target}.sig\n`);
126
+ process.exit(0);
127
+ } catch (e) {
128
+ die(`Sign failed: ${e.message}`);
129
+ }
130
+ }
131
+
132
+ if (cmd === 'verify') {
133
+ const target = args.find(a => !a.startsWith('--'));
134
+ if (!target) die('Usage: agentic-security-rule verify <rule-yml>');
135
+ if (!fs.existsSync(target)) die(`File not found: ${target}`);
136
+ const scanRoot = path.resolve('.');
137
+ const keys = loadTrustedKeys(scanRoot);
138
+ if (keys.length === 0) {
139
+ process.stderr.write('agentic-security-rule: no trusted keys configured.\n');
140
+ process.stderr.write(' Add keys to .agentic-security/trusted-keys.json and set AGENTIC_SECURITY_ALLOW_PROJECT_KEYS=1.\n');
141
+ process.exit(2);
142
+ }
143
+ const r = verifyRulePack(target, keys);
144
+ if (r.ok) {
145
+ process.stdout.write(`OK — signed by ${r.keyId}\n`);
146
+ process.exit(0);
147
+ } else {
148
+ process.stderr.write(`FAILED: ${r.reason}${r.keyId ? ` (key ${r.keyId})` : ''}\n`);
149
+ process.exit(1);
150
+ }
151
+ }
152
+
153
+ die(`Usage: agentic-security-rule <keygen | sign <rule.yml> | verify <rule.yml>>`);