vaspera 2.13.0 → 2.15.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 (300) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +15 -2
  3. package/dist/__tests__/antagonist-integration.test.d.ts +6 -0
  4. package/dist/__tests__/antagonist-integration.test.d.ts.map +1 -0
  5. package/dist/__tests__/antagonist-integration.test.js +239 -0
  6. package/dist/__tests__/antagonist-integration.test.js.map +1 -0
  7. package/dist/__tests__/certification/agent-certificate-e2e.test.d.ts +2 -0
  8. package/dist/__tests__/certification/agent-certificate-e2e.test.d.ts.map +1 -0
  9. package/dist/__tests__/certification/agent-certificate-e2e.test.js +90 -0
  10. package/dist/__tests__/certification/agent-certificate-e2e.test.js.map +1 -0
  11. package/dist/__tests__/certification/agent-certificate-map.test.d.ts +2 -0
  12. package/dist/__tests__/certification/agent-certificate-map.test.d.ts.map +1 -0
  13. package/dist/__tests__/certification/agent-certificate-map.test.js +107 -0
  14. package/dist/__tests__/certification/agent-certificate-map.test.js.map +1 -0
  15. package/dist/__tests__/certification/agent-certificate.test.d.ts +2 -0
  16. package/dist/__tests__/certification/agent-certificate.test.d.ts.map +1 -0
  17. package/dist/__tests__/certification/agent-certificate.test.js +78 -0
  18. package/dist/__tests__/certification/agent-certificate.test.js.map +1 -0
  19. package/dist/__tests__/certification/verify-endpoint.test.d.ts +2 -0
  20. package/dist/__tests__/certification/verify-endpoint.test.d.ts.map +1 -0
  21. package/dist/__tests__/certification/verify-endpoint.test.js +81 -0
  22. package/dist/__tests__/certification/verify-endpoint.test.js.map +1 -0
  23. package/dist/__tests__/compliance/ai-frameworks.test.d.ts +2 -0
  24. package/dist/__tests__/compliance/ai-frameworks.test.d.ts.map +1 -0
  25. package/dist/__tests__/compliance/ai-frameworks.test.js +87 -0
  26. package/dist/__tests__/compliance/ai-frameworks.test.js.map +1 -0
  27. package/dist/__tests__/eval/llm-analyzer.test.d.ts +2 -0
  28. package/dist/__tests__/eval/llm-analyzer.test.d.ts.map +1 -0
  29. package/dist/__tests__/eval/llm-analyzer.test.js +93 -0
  30. package/dist/__tests__/eval/llm-analyzer.test.js.map +1 -0
  31. package/dist/__tests__/eval/redteam-harness.test.d.ts +2 -0
  32. package/dist/__tests__/eval/redteam-harness.test.d.ts.map +1 -0
  33. package/dist/__tests__/eval/redteam-harness.test.js +136 -0
  34. package/dist/__tests__/eval/redteam-harness.test.js.map +1 -0
  35. package/dist/__tests__/evidence/evidence.test.d.ts +2 -0
  36. package/dist/__tests__/evidence/evidence.test.d.ts.map +1 -0
  37. package/dist/__tests__/evidence/evidence.test.js +240 -0
  38. package/dist/__tests__/evidence/evidence.test.js.map +1 -0
  39. package/dist/__tests__/history/decisions.test.d.ts +2 -0
  40. package/dist/__tests__/history/decisions.test.d.ts.map +1 -0
  41. package/dist/__tests__/history/decisions.test.js +54 -0
  42. package/dist/__tests__/history/decisions.test.js.map +1 -0
  43. package/dist/__tests__/http-auth.test.d.ts +2 -0
  44. package/dist/__tests__/http-auth.test.d.ts.map +1 -0
  45. package/dist/__tests__/http-auth.test.js +55 -0
  46. package/dist/__tests__/http-auth.test.js.map +1 -0
  47. package/dist/__tests__/http-policy.test.d.ts +2 -0
  48. package/dist/__tests__/http-policy.test.d.ts.map +1 -0
  49. package/dist/__tests__/http-policy.test.js +69 -0
  50. package/dist/__tests__/http-policy.test.js.map +1 -0
  51. package/dist/__tests__/http-server-transport.test.d.ts +2 -0
  52. package/dist/__tests__/http-server-transport.test.d.ts.map +1 -0
  53. package/dist/__tests__/http-server-transport.test.js +132 -0
  54. package/dist/__tests__/http-server-transport.test.js.map +1 -0
  55. package/dist/__tests__/integration/destructive-guards.test.d.ts +2 -0
  56. package/dist/__tests__/integration/destructive-guards.test.d.ts.map +1 -0
  57. package/dist/__tests__/integration/destructive-guards.test.js +49 -0
  58. package/dist/__tests__/integration/destructive-guards.test.js.map +1 -0
  59. package/dist/__tests__/logger-redaction.test.d.ts +2 -0
  60. package/dist/__tests__/logger-redaction.test.d.ts.map +1 -0
  61. package/dist/__tests__/logger-redaction.test.js +74 -0
  62. package/dist/__tests__/logger-redaction.test.js.map +1 -0
  63. package/dist/__tests__/manifest-schema.test.d.ts +2 -0
  64. package/dist/__tests__/manifest-schema.test.d.ts.map +1 -0
  65. package/dist/__tests__/manifest-schema.test.js +43 -0
  66. package/dist/__tests__/manifest-schema.test.js.map +1 -0
  67. package/dist/__tests__/scanners/builtin-rules.test.d.ts +2 -0
  68. package/dist/__tests__/scanners/builtin-rules.test.d.ts.map +1 -0
  69. package/dist/__tests__/scanners/builtin-rules.test.js +51 -0
  70. package/dist/__tests__/scanners/builtin-rules.test.js.map +1 -0
  71. package/dist/__tests__/scanners/runtime/golden-path-runner.test.js +13 -1
  72. package/dist/__tests__/scanners/runtime/golden-path-runner.test.js.map +1 -1
  73. package/dist/__tests__/tool-guard.test.d.ts +2 -0
  74. package/dist/__tests__/tool-guard.test.d.ts.map +1 -0
  75. package/dist/__tests__/tool-guard.test.js +97 -0
  76. package/dist/__tests__/tool-guard.test.js.map +1 -0
  77. package/dist/__tests__/util/contained-file.test.d.ts +2 -0
  78. package/dist/__tests__/util/contained-file.test.d.ts.map +1 -0
  79. package/dist/__tests__/util/contained-file.test.js +78 -0
  80. package/dist/__tests__/util/contained-file.test.js.map +1 -0
  81. package/dist/__tests__/util/subprocess.test.d.ts +2 -0
  82. package/dist/__tests__/util/subprocess.test.d.ts.map +1 -0
  83. package/dist/__tests__/util/subprocess.test.js +48 -0
  84. package/dist/__tests__/util/subprocess.test.js.map +1 -0
  85. package/dist/action/diff-mode.d.ts.map +1 -1
  86. package/dist/action/diff-mode.js +31 -12
  87. package/dist/action/diff-mode.js.map +1 -1
  88. package/dist/agents/antagonist/challenger.d.ts +46 -0
  89. package/dist/agents/antagonist/challenger.d.ts.map +1 -0
  90. package/dist/agents/antagonist/challenger.js +257 -0
  91. package/dist/agents/antagonist/challenger.js.map +1 -0
  92. package/dist/agents/antagonist/index.d.ts +31 -0
  93. package/dist/agents/antagonist/index.d.ts.map +1 -0
  94. package/dist/agents/antagonist/index.js +175 -0
  95. package/dist/agents/antagonist/index.js.map +1 -0
  96. package/dist/agents/antagonist/prioritizer.d.ts +27 -0
  97. package/dist/agents/antagonist/prioritizer.d.ts.map +1 -0
  98. package/dist/agents/antagonist/prioritizer.js +181 -0
  99. package/dist/agents/antagonist/prioritizer.js.map +1 -0
  100. package/dist/agents/antagonist/prompts.d.ts +12 -0
  101. package/dist/agents/antagonist/prompts.d.ts.map +1 -0
  102. package/dist/agents/antagonist/prompts.js +155 -0
  103. package/dist/agents/antagonist/prompts.js.map +1 -0
  104. package/dist/agents/antagonist/synthesizer.d.ts +34 -0
  105. package/dist/agents/antagonist/synthesizer.d.ts.map +1 -0
  106. package/dist/agents/antagonist/synthesizer.js +451 -0
  107. package/dist/agents/antagonist/synthesizer.js.map +1 -0
  108. package/dist/agents/antagonist/types.d.ts +145 -0
  109. package/dist/agents/antagonist/types.d.ts.map +1 -0
  110. package/dist/agents/antagonist/types.js +63 -0
  111. package/dist/agents/antagonist/types.js.map +1 -0
  112. package/dist/agents/index.d.ts +1 -0
  113. package/dist/agents/index.d.ts.map +1 -1
  114. package/dist/agents/index.js +2 -0
  115. package/dist/agents/index.js.map +1 -1
  116. package/dist/certification/agent-certificate-map.d.ts +51 -0
  117. package/dist/certification/agent-certificate-map.d.ts.map +1 -0
  118. package/dist/certification/agent-certificate-map.js +265 -0
  119. package/dist/certification/agent-certificate-map.js.map +1 -0
  120. package/dist/certification/agent-certificate-sample.d.ts +25 -0
  121. package/dist/certification/agent-certificate-sample.d.ts.map +1 -0
  122. package/dist/certification/agent-certificate-sample.js +207 -0
  123. package/dist/certification/agent-certificate-sample.js.map +1 -0
  124. package/dist/certification/agent-certificate.d.ts +1981 -0
  125. package/dist/certification/agent-certificate.d.ts.map +1 -0
  126. package/dist/certification/agent-certificate.js +309 -0
  127. package/dist/certification/agent-certificate.js.map +1 -0
  128. package/dist/certification/autofix.d.ts.map +1 -1
  129. package/dist/certification/autofix.js +5 -3
  130. package/dist/certification/autofix.js.map +1 -1
  131. package/dist/certification/consensus.test.js +2 -0
  132. package/dist/certification/consensus.test.js.map +1 -1
  133. package/dist/certification/store.d.ts.map +1 -1
  134. package/dist/certification/store.js +11 -3
  135. package/dist/certification/store.js.map +1 -1
  136. package/dist/certification/types.d.ts +1 -1
  137. package/dist/certification/types.d.ts.map +1 -1
  138. package/dist/certification/types.js +2 -0
  139. package/dist/certification/types.js.map +1 -1
  140. package/dist/certification/verify-endpoint.d.ts +48 -0
  141. package/dist/certification/verify-endpoint.d.ts.map +1 -0
  142. package/dist/certification/verify-endpoint.js +79 -0
  143. package/dist/certification/verify-endpoint.js.map +1 -0
  144. package/dist/compliance/index.d.ts +2 -0
  145. package/dist/compliance/index.d.ts.map +1 -1
  146. package/dist/compliance/index.js +4 -0
  147. package/dist/compliance/index.js.map +1 -1
  148. package/dist/compliance/iso42001.d.ts +21 -0
  149. package/dist/compliance/iso42001.d.ts.map +1 -0
  150. package/dist/compliance/iso42001.js +160 -0
  151. package/dist/compliance/iso42001.js.map +1 -0
  152. package/dist/compliance/mapper.d.ts.map +1 -1
  153. package/dist/compliance/mapper.js +12 -0
  154. package/dist/compliance/mapper.js.map +1 -1
  155. package/dist/compliance/nist-ai-rmf.d.ts +20 -0
  156. package/dist/compliance/nist-ai-rmf.d.ts.map +1 -0
  157. package/dist/compliance/nist-ai-rmf.js +140 -0
  158. package/dist/compliance/nist-ai-rmf.js.map +1 -0
  159. package/dist/config/flags.d.ts +4 -4
  160. package/dist/eval/fixtures.d.ts.map +1 -1
  161. package/dist/eval/fixtures.js +161 -119
  162. package/dist/eval/fixtures.js.map +1 -1
  163. package/dist/eval/fixtures.test.js +4 -2
  164. package/dist/eval/fixtures.test.js.map +1 -1
  165. package/dist/eval/llm-analyzer.d.ts +40 -0
  166. package/dist/eval/llm-analyzer.d.ts.map +1 -0
  167. package/dist/eval/llm-analyzer.js +154 -0
  168. package/dist/eval/llm-analyzer.js.map +1 -0
  169. package/dist/eval/redteam-harness.d.ts +95 -0
  170. package/dist/eval/redteam-harness.d.ts.map +1 -0
  171. package/dist/eval/redteam-harness.js +137 -0
  172. package/dist/eval/redteam-harness.js.map +1 -0
  173. package/dist/evidence/collector.d.ts.map +1 -1
  174. package/dist/evidence/collector.js +21 -1
  175. package/dist/evidence/collector.js.map +1 -1
  176. package/dist/evidence/store.d.ts.map +1 -1
  177. package/dist/evidence/store.js +29 -5
  178. package/dist/evidence/store.js.map +1 -1
  179. package/dist/evidence/types.d.ts +16 -9
  180. package/dist/evidence/types.d.ts.map +1 -1
  181. package/dist/history/decisions.d.ts +63 -0
  182. package/dist/history/decisions.d.ts.map +1 -0
  183. package/dist/history/decisions.js +60 -0
  184. package/dist/history/decisions.js.map +1 -0
  185. package/dist/history/index.d.ts +2 -0
  186. package/dist/history/index.d.ts.map +1 -1
  187. package/dist/history/index.js +2 -0
  188. package/dist/history/index.js.map +1 -1
  189. package/dist/history/types.d.ts +34 -5
  190. package/dist/history/types.d.ts.map +1 -1
  191. package/dist/history/types.js +2 -0
  192. package/dist/history/types.js.map +1 -1
  193. package/dist/http-auth.d.ts +22 -0
  194. package/dist/http-auth.d.ts.map +1 -0
  195. package/dist/http-auth.js +58 -0
  196. package/dist/http-auth.js.map +1 -0
  197. package/dist/http-policy.d.ts +30 -0
  198. package/dist/http-policy.d.ts.map +1 -0
  199. package/dist/http-policy.js +54 -0
  200. package/dist/http-policy.js.map +1 -0
  201. package/dist/http-server.js +195 -12
  202. package/dist/http-server.js.map +1 -1
  203. package/dist/index.d.ts.map +1 -1
  204. package/dist/index.js +411 -15
  205. package/dist/index.js.map +1 -1
  206. package/dist/logger.d.ts.map +1 -1
  207. package/dist/logger.js +56 -2
  208. package/dist/logger.js.map +1 -1
  209. package/dist/plugins/types.d.ts +2 -2
  210. package/dist/sbom/provenance.test.js +2 -2
  211. package/dist/sbom/provenance.test.js.map +1 -1
  212. package/dist/sbom/signing.d.ts.map +1 -1
  213. package/dist/sbom/signing.js +5 -3
  214. package/dist/sbom/signing.js.map +1 -1
  215. package/dist/scanners/agent/prompt-injection-fuzzer.d.ts.map +1 -1
  216. package/dist/scanners/agent/prompt-injection-fuzzer.js +26 -0
  217. package/dist/scanners/agent/prompt-injection-fuzzer.js.map +1 -1
  218. package/dist/scanners/agent/types.d.ts +10 -10
  219. package/dist/scanners/bandit.d.ts.map +1 -1
  220. package/dist/scanners/bandit.js +35 -29
  221. package/dist/scanners/bandit.js.map +1 -1
  222. package/dist/scanners/binary-analysis.d.ts.map +1 -1
  223. package/dist/scanners/binary-analysis.js +24 -49
  224. package/dist/scanners/binary-analysis.js.map +1 -1
  225. package/dist/scanners/brakeman.d.ts.map +1 -1
  226. package/dist/scanners/brakeman.js +19 -33
  227. package/dist/scanners/brakeman.js.map +1 -1
  228. package/dist/scanners/builtin-rules.d.ts +24 -0
  229. package/dist/scanners/builtin-rules.d.ts.map +1 -0
  230. package/dist/scanners/builtin-rules.js +175 -0
  231. package/dist/scanners/builtin-rules.js.map +1 -0
  232. package/dist/scanners/dast.d.ts.map +1 -1
  233. package/dist/scanners/dast.js +24 -34
  234. package/dist/scanners/dast.js.map +1 -1
  235. package/dist/scanners/deploy/types.d.ts +6 -6
  236. package/dist/scanners/eslint.d.ts.map +1 -1
  237. package/dist/scanners/eslint.js +15 -24
  238. package/dist/scanners/eslint.js.map +1 -1
  239. package/dist/scanners/gosec.d.ts.map +1 -1
  240. package/dist/scanners/gosec.js +14 -62
  241. package/dist/scanners/gosec.js.map +1 -1
  242. package/dist/scanners/index.d.ts.map +1 -1
  243. package/dist/scanners/index.js +38 -7
  244. package/dist/scanners/index.js.map +1 -1
  245. package/dist/scanners/memory-safety.d.ts.map +1 -1
  246. package/dist/scanners/memory-safety.js +27 -28
  247. package/dist/scanners/memory-safety.js.map +1 -1
  248. package/dist/scanners/openapi.d.ts.map +1 -1
  249. package/dist/scanners/openapi.js +14 -22
  250. package/dist/scanners/openapi.js.map +1 -1
  251. package/dist/scanners/race-condition.d.ts.map +1 -1
  252. package/dist/scanners/race-condition.js +17 -16
  253. package/dist/scanners/race-condition.js.map +1 -1
  254. package/dist/scanners/runtime/types.d.ts +4 -4
  255. package/dist/scanners/rust.d.ts.map +1 -1
  256. package/dist/scanners/rust.js +38 -37
  257. package/dist/scanners/rust.js.map +1 -1
  258. package/dist/scanners/scale/types.d.ts +16 -16
  259. package/dist/scanners/secrets.d.ts.map +1 -1
  260. package/dist/scanners/secrets.js +66 -78
  261. package/dist/scanners/secrets.js.map +1 -1
  262. package/dist/scanners/semgrep.d.ts +2 -0
  263. package/dist/scanners/semgrep.d.ts.map +1 -1
  264. package/dist/scanners/semgrep.js +12 -0
  265. package/dist/scanners/semgrep.js.map +1 -1
  266. package/dist/scanners/terraform.d.ts.map +1 -1
  267. package/dist/scanners/terraform.js +47 -40
  268. package/dist/scanners/terraform.js.map +1 -1
  269. package/dist/scanners/trivy.d.ts.map +1 -1
  270. package/dist/scanners/trivy.js +38 -30
  271. package/dist/scanners/trivy.js.map +1 -1
  272. package/dist/tool-guard.d.ts +40 -0
  273. package/dist/tool-guard.d.ts.map +1 -0
  274. package/dist/tool-guard.js +55 -0
  275. package/dist/tool-guard.js.map +1 -0
  276. package/dist/util/index.d.ts +2 -1
  277. package/dist/util/index.d.ts.map +1 -1
  278. package/dist/util/index.js +2 -1
  279. package/dist/util/index.js.map +1 -1
  280. package/dist/util/paths.d.ts +20 -3
  281. package/dist/util/paths.d.ts.map +1 -1
  282. package/dist/util/paths.js +84 -4
  283. package/dist/util/paths.js.map +1 -1
  284. package/dist/util/subprocess.d.ts +51 -0
  285. package/dist/util/subprocess.d.ts.map +1 -0
  286. package/dist/util/subprocess.js +77 -0
  287. package/dist/util/subprocess.js.map +1 -0
  288. package/package.json +12 -2
  289. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts +0 -28
  290. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts.map +0 -1
  291. package/dist/eval/fixtures/healthcare/audit-gaps.js +0 -90
  292. package/dist/eval/fixtures/healthcare/audit-gaps.js.map +0 -1
  293. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts +0 -31
  294. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts.map +0 -1
  295. package/dist/eval/fixtures/healthcare/consent-bypass.js +0 -61
  296. package/dist/eval/fixtures/healthcare/consent-bypass.js.map +0 -1
  297. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts +0 -24
  298. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts.map +0 -1
  299. package/dist/eval/fixtures/healthcare/phi-in-logs.js +0 -41
  300. package/dist/eval/fixtures/healthcare/phi-in-logs.js.map +0 -1
@@ -0,0 +1,20 @@
1
+ /**
2
+ * NIST AI Risk Management Framework (AI RMF 1.0) + Generative AI Profile
3
+ *
4
+ * The four functions — GOVERN, MAP, MEASURE, MANAGE — and their key
5
+ * subcategories, mapped to the platform's finding categories. US-friendly
6
+ * and becoming the de facto AI governance baseline.
7
+ *
8
+ * @module compliance/nist-ai-rmf
9
+ */
10
+ import type { ComplianceControl } from "./types.js";
11
+ /**
12
+ * NIST AI RMF controls (representative subcategories relevant to
13
+ * certifying AI systems and AI-generated code).
14
+ */
15
+ export declare const NIST_AI_RMF_CONTROLS: ComplianceControl[];
16
+ /** Get all NIST AI RMF controls. */
17
+ export declare function getNISTAIRMFControls(): ComplianceControl[];
18
+ /** Get NIST AI RMF controls for a given function (GOVERN/MAP/MEASURE/MANAGE). */
19
+ export declare function getNISTAIRMFControlsByFunction(fn: string): ComplianceControl[];
20
+ //# sourceMappingURL=nist-ai-rmf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nist-ai-rmf.d.ts","sourceRoot":"","sources":["../../src/compliance/nist-ai-rmf.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,EAmInD,CAAC;AAEF,oCAAoC;AACpC,wBAAgB,oBAAoB,IAAI,iBAAiB,EAAE,CAE1D;AAED,iFAAiF;AACjF,wBAAgB,8BAA8B,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAE9E"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * NIST AI Risk Management Framework (AI RMF 1.0) + Generative AI Profile
3
+ *
4
+ * The four functions — GOVERN, MAP, MEASURE, MANAGE — and their key
5
+ * subcategories, mapped to the platform's finding categories. US-friendly
6
+ * and becoming the de facto AI governance baseline.
7
+ *
8
+ * @module compliance/nist-ai-rmf
9
+ */
10
+ /**
11
+ * NIST AI RMF controls (representative subcategories relevant to
12
+ * certifying AI systems and AI-generated code).
13
+ */
14
+ export const NIST_AI_RMF_CONTROLS = [
15
+ // GOVERN — policies, accountability, culture
16
+ {
17
+ id: "GOVERN-1.1",
18
+ framework: "NIST-AI-RMF",
19
+ category: "GOVERN",
20
+ title: "Legal and policy requirements are understood and managed",
21
+ description: "Policies, processes, and practices for AI risk management are in place, transparent, and implemented.",
22
+ keywords: ["policy", "governance", "accountability", "compliance"],
23
+ findingCategories: ["security-misconfiguration"],
24
+ severityThreshold: "low",
25
+ },
26
+ {
27
+ id: "GOVERN-1.5",
28
+ framework: "NIST-AI-RMF",
29
+ category: "GOVERN",
30
+ title: "Ongoing monitoring and periodic review are planned",
31
+ description: "Mechanisms exist to monitor AI systems and detect drift in tools, models, and agent behavior over time.",
32
+ keywords: ["monitoring", "review", "drift", "ongoing"],
33
+ findingCategories: ["tool-drift", "manifest-drift"],
34
+ severityThreshold: "medium",
35
+ },
36
+ {
37
+ id: "GOVERN-6.1",
38
+ framework: "NIST-AI-RMF",
39
+ category: "GOVERN",
40
+ title: "Third-party risks are managed",
41
+ description: "Risks associated with third-party models, datasets, tools, and software (including MCP servers) are identified and managed.",
42
+ keywords: ["third party", "supply chain", "vendor", "external"],
43
+ findingCategories: ["supply-chain-vuln", "unsigned-change"],
44
+ severityThreshold: "medium",
45
+ },
46
+ // MAP — context and risk identification
47
+ {
48
+ id: "MAP-1.1",
49
+ framework: "NIST-AI-RMF",
50
+ category: "MAP",
51
+ title: "Intended purpose and context are established",
52
+ description: "The AI system's intended purpose, scope, and operating context — including the bounds of agent autonomy — are documented.",
53
+ keywords: ["intended use", "context", "scope", "autonomy"],
54
+ findingCategories: ["excessive-agency", "overreliance"],
55
+ severityThreshold: "medium",
56
+ },
57
+ {
58
+ id: "MAP-5.1",
59
+ framework: "NIST-AI-RMF",
60
+ category: "MAP",
61
+ title: "Impacts to individuals and society are characterized",
62
+ description: "Likelihood and magnitude of impacts, including privacy and data-exposure harms, are identified.",
63
+ keywords: ["impact", "privacy", "harm", "exposure"],
64
+ findingCategories: ["pii-exposure", "sensitive-disclosure"],
65
+ severityThreshold: "medium",
66
+ },
67
+ // MEASURE — trustworthiness characteristics
68
+ {
69
+ id: "MEASURE-2.6",
70
+ framework: "NIST-AI-RMF",
71
+ category: "MEASURE",
72
+ title: "AI system is evaluated for safety and security/resilience",
73
+ description: "The AI system is tested for resistance to adversarial manipulation, including prompt injection and insecure output handling.",
74
+ keywords: ["security", "resilience", "adversarial", "prompt injection", "robustness"],
75
+ findingCategories: ["prompt-injection", "insecure-output", "model-denial-of-service"],
76
+ cweIds: ["CWE-77", "CWE-94"],
77
+ severityThreshold: "high",
78
+ },
79
+ {
80
+ id: "MEASURE-2.7",
81
+ framework: "NIST-AI-RMF",
82
+ category: "MEASURE",
83
+ title: "AI system security and data exfiltration risks are assessed",
84
+ description: "Paths by which secrets or sensitive data could be exfiltrated through the AI system are assessed and mitigated.",
85
+ keywords: ["exfiltration", "data leak", "secret", "credential"],
86
+ findingCategories: ["exfil-path", "hardcoded-secret", "credential-overscoped"],
87
+ severityThreshold: "high",
88
+ },
89
+ {
90
+ id: "MEASURE-2.9",
91
+ framework: "NIST-AI-RMF",
92
+ category: "MEASURE",
93
+ title: "AI model is explainable and decisions are traceable",
94
+ description: "Mechanisms exist to trace and explain AI system decisions, supported by tamper-evident records.",
95
+ keywords: ["explainability", "traceability", "provenance", "audit"],
96
+ findingCategories: ["unsigned-change", "consensus-manipulation"],
97
+ severityThreshold: "medium",
98
+ },
99
+ {
100
+ id: "MEASURE-2.10",
101
+ framework: "NIST-AI-RMF",
102
+ category: "MEASURE",
103
+ title: "Privacy risk is assessed",
104
+ description: "Privacy risks, including exposure of personal data through model inputs or outputs, are measured.",
105
+ keywords: ["privacy", "pii", "personal data"],
106
+ findingCategories: ["pii-exposure"],
107
+ severityThreshold: "high",
108
+ },
109
+ // MANAGE — risk treatment and response
110
+ {
111
+ id: "MANAGE-2.2",
112
+ framework: "NIST-AI-RMF",
113
+ category: "MANAGE",
114
+ title: "Mechanisms to mitigate identified risks are applied",
115
+ description: "Controls (least privilege, sandboxing, scoping) are applied to mitigate risks from agent tools and permissions.",
116
+ keywords: ["mitigation", "least privilege", "sandbox", "scope", "permission"],
117
+ findingCategories: ["overscoped-permission", "missing-sandbox", "excessive-agency"],
118
+ cweIds: ["CWE-250", "CWE-269"],
119
+ severityThreshold: "high",
120
+ },
121
+ {
122
+ id: "MANAGE-4.1",
123
+ framework: "NIST-AI-RMF",
124
+ category: "MANAGE",
125
+ title: "Post-deployment monitoring and incident response are in place",
126
+ description: "AI systems are monitored after deployment for emergent risks, with response mechanisms for detected issues.",
127
+ keywords: ["post-deployment", "incident response", "monitoring", "emergent"],
128
+ findingCategories: ["insecure-plugin", "model-theft"],
129
+ severityThreshold: "medium",
130
+ },
131
+ ];
132
+ /** Get all NIST AI RMF controls. */
133
+ export function getNISTAIRMFControls() {
134
+ return NIST_AI_RMF_CONTROLS;
135
+ }
136
+ /** Get NIST AI RMF controls for a given function (GOVERN/MAP/MEASURE/MANAGE). */
137
+ export function getNISTAIRMFControlsByFunction(fn) {
138
+ return NIST_AI_RMF_CONTROLS.filter((c) => c.category === fn);
139
+ }
140
+ //# sourceMappingURL=nist-ai-rmf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nist-ai-rmf.js","sourceRoot":"","sources":["../../src/compliance/nist-ai-rmf.ts"],"names":[],"mappings":"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"}
@@ -306,14 +306,14 @@ export declare const VasperaConfigSchema: z.ZodObject<{
306
306
  configs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
307
307
  }, "strip", z.ZodTypeAny, {
308
308
  configs: Record<string, Record<string, unknown>>;
309
+ sandbox: boolean;
309
310
  loadLocal: boolean;
310
311
  loadNpm: boolean;
311
- sandbox: boolean;
312
312
  }, {
313
313
  configs?: Record<string, Record<string, unknown>> | undefined;
314
+ sandbox?: boolean | undefined;
314
315
  loadLocal?: boolean | undefined;
315
316
  loadNpm?: boolean | undefined;
316
- sandbox?: boolean | undefined;
317
317
  }>>;
318
318
  }, "strip", z.ZodTypeAny, {
319
319
  version: 1;
@@ -332,9 +332,9 @@ export declare const VasperaConfigSchema: z.ZodObject<{
332
332
  }>;
333
333
  plugins: {
334
334
  configs: Record<string, Record<string, unknown>>;
335
+ sandbox: boolean;
335
336
  loadLocal: boolean;
336
337
  loadNpm: boolean;
337
- sandbox: boolean;
338
338
  };
339
339
  cost: {
340
340
  warningThreshold: number;
@@ -380,9 +380,9 @@ export declare const VasperaConfigSchema: z.ZodObject<{
380
380
  }> | undefined;
381
381
  plugins?: {
382
382
  configs?: Record<string, Record<string, unknown>> | undefined;
383
+ sandbox?: boolean | undefined;
383
384
  loadLocal?: boolean | undefined;
384
385
  loadNpm?: boolean | undefined;
385
- sandbox?: boolean | undefined;
386
386
  } | undefined;
387
387
  cost?: {
388
388
  maxBudget?: number | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/eval/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAAW,EA0F7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,EA2GpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,EAmGxC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,EA+F3C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,EA6CrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,EAyD9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,EA4EjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,EAsFrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,EA6CpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,+BAA+B,EAAE,WAAW,EA0FxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,EA4G1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,EAYrC,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAErE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAE3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAElE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,CAcA"}
1
+ {"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/eval/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAAW,EAgG7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,EA+HpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,EAmGxC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,EA+F3C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,EA6CrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,EA4D9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,EAmFjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,EA4FrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,EA6CpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,+BAA+B,EAAE,WAAW,EA0FxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,EA4G1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,EAYrC,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAErE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAE3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAElE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,CAcA"}
@@ -21,31 +21,33 @@ export const sqlInjectionFixtures = [
21
21
  path: "db.ts",
22
22
  language: "typescript",
23
23
  content: `import { Pool } from 'pg';
24
+ import express from 'express';
24
25
 
25
26
  const pool = new Pool();
27
+ const app = express();
26
28
 
27
- // VULNERABLE: SQL injection via string concatenation
28
- export async function getUserByName(name: string) {
29
+ // VULNERABLE: request input concatenated into a SQL query
30
+ app.get('/users', (req, res) => {
31
+ const name = req.query.name;
29
32
  const query = "SELECT * FROM users WHERE name = '" + name + "'";
30
- return pool.query(query);
31
- }
33
+ pool.query(query).then((r) => res.json(r.rows));
34
+ });
32
35
 
33
- // SAFE: Parameterized query
34
- export async function getUserById(id: number) {
35
- const query = "SELECT * FROM users WHERE id = $1";
36
- return pool.query(query, [id]);
37
- }
36
+ // SAFE: parameterized query
37
+ app.get('/user', (req, res) => {
38
+ pool.query("SELECT * FROM users WHERE id = $1", [req.query.id]);
39
+ });
38
40
  `,
39
41
  },
40
42
  ],
41
43
  expectedFindings: [
42
44
  {
43
45
  file: "db.ts",
44
- line: 7,
46
+ line: 12,
45
47
  severity: "critical",
46
48
  category: "sql-injection",
47
49
  cweId: "CWE-89",
48
- description: "SQL injection via string concatenation",
50
+ description: "SQL injection via string concatenation of request input",
49
51
  isVulnerable: true,
50
52
  },
51
53
  ],
@@ -62,25 +64,29 @@ export async function getUserById(id: number) {
62
64
  path: "search.ts",
63
65
  language: "typescript",
64
66
  content: `import { db } from './connection';
67
+ import express from 'express';
68
+
69
+ const app = express();
65
70
 
66
- // VULNERABLE: Template literal injection
67
- export async function searchProducts(term: string) {
71
+ // VULNERABLE: template-literal injection from request input
72
+ app.get('/search', (req, res) => {
73
+ const term = req.query.term;
68
74
  const sql = \`SELECT * FROM products WHERE name LIKE '%\${term}%'\`;
69
- return db.query(sql);
70
- }
75
+ db.query(sql).then((r) => res.json(r));
76
+ });
71
77
 
72
- // VULNERABLE: Dynamic ORDER BY
73
- export async function listUsers(sortBy: string) {
74
- const sql = \`SELECT * FROM users ORDER BY \${sortBy}\`;
75
- return db.query(sql);
76
- }
78
+ // VULNERABLE: dynamic ORDER BY from request input
79
+ app.get('/list', (req, res) => {
80
+ const sql = \`SELECT * FROM users ORDER BY \${req.query.sortBy}\`;
81
+ db.query(sql);
82
+ });
77
83
  `,
78
84
  },
79
85
  ],
80
86
  expectedFindings: [
81
87
  {
82
88
  file: "search.ts",
83
- line: 5,
89
+ line: 9,
84
90
  severity: "critical",
85
91
  category: "sql-injection",
86
92
  cweId: "CWE-89",
@@ -89,7 +95,7 @@ export async function listUsers(sortBy: string) {
89
95
  },
90
96
  {
91
97
  file: "search.ts",
92
- line: 11,
98
+ line: 15,
93
99
  severity: "high",
94
100
  category: "sql-injection",
95
101
  cweId: "CWE-89",
@@ -165,46 +171,66 @@ export function SafeProfile({ bio }: Props) {
165
171
  {
166
172
  path: "comment.ts",
167
173
  language: "typescript",
168
- content: `// VULNERABLE: innerHTML with user input
169
- export function renderComment(userComment: string) {
170
- const container = document.getElementById('comments');
171
- if (container) {
172
- container.innerHTML = userComment;
173
- }
174
- }
174
+ content: `import express from 'express';
175
175
 
176
- // VULNERABLE: document.write
177
- export function writeMessage(message: string) {
178
- document.write('<div>' + message + '</div>');
179
- }
176
+ const app = express();
180
177
 
181
- // SAFE: textContent
182
- export function renderSafeComment(userComment: string) {
183
- const container = document.getElementById('comments');
184
- if (container) {
185
- container.textContent = userComment;
186
- }
187
- }
178
+ // VULNERABLE: Reflected XSS via res.send with unescaped req.query
179
+ app.get('/comment', (req, res) => {
180
+ const userComment = req.query.text;
181
+ res.send('<div>' + userComment + '</div>');
182
+ });
183
+
184
+ // VULNERABLE: Reflected XSS via res.write with unescaped req.query
185
+ app.get('/message', (req, res) => {
186
+ const message = req.query.msg;
187
+ res.write('<div>' + message + '</div>');
188
+ res.end();
189
+ });
190
+
191
+ // SAFE: JSON response, not HTML
192
+ app.get('/safe-comment', (req, res) => {
193
+ const userComment = req.query.text;
194
+ res.json({ comment: userComment });
195
+ });
188
196
  `,
189
197
  },
190
198
  ],
191
199
  expectedFindings: [
192
200
  {
193
201
  file: "comment.ts",
194
- line: 5,
202
+ line: 8,
195
203
  severity: "high",
196
204
  category: "xss",
197
205
  cweId: "CWE-79",
198
- description: "XSS via innerHTML",
206
+ description: "Reflected XSS via res.send with unescaped request input",
199
207
  isVulnerable: true,
200
208
  },
201
209
  {
202
210
  file: "comment.ts",
203
- line: 11,
211
+ line: 8,
212
+ severity: "high",
213
+ category: "xss",
214
+ cweId: "CWE-79",
215
+ description: "Reflected XSS: unsanitized request input written to HTTP response",
216
+ isVulnerable: true,
217
+ },
218
+ {
219
+ file: "comment.ts",
220
+ line: 14,
221
+ severity: "high",
222
+ category: "xss",
223
+ cweId: "CWE-79",
224
+ description: "Reflected XSS via res.write with unescaped request input",
225
+ isVulnerable: true,
226
+ },
227
+ {
228
+ file: "comment.ts",
229
+ line: 14,
204
230
  severity: "high",
205
231
  category: "xss",
206
232
  cweId: "CWE-79",
207
- description: "XSS via document.write",
233
+ description: "Reflected XSS: unsanitized request input streamed to HTTP response",
208
234
  isVulnerable: true,
209
235
  },
210
236
  ],
@@ -477,46 +503,49 @@ export const pathTraversalFixtures = [
477
503
  path: "files.ts",
478
504
  language: "typescript",
479
505
  content: `import { readFile } from 'fs/promises';
506
+ import { createReadStream } from 'fs';
480
507
  import { join } from 'path';
508
+ import express from 'express';
509
+
510
+ const app = express();
481
511
 
482
512
  // VULNERABLE: Direct user input in path
483
- export async function getFile(filename: string) {
484
- const content = await readFile(filename, 'utf-8');
485
- return content;
486
- }
513
+ app.get('/file', (req, res) => {
514
+ const filename = req.query.name as string;
515
+ readFile(filename, 'utf-8').then((content) => res.send(content));
516
+ });
487
517
 
488
- // VULNERABLE: Path traversal possible
489
- export async function getDocument(docName: string) {
490
- const path = './documents/' + docName;
491
- return readFile(path, 'utf-8');
492
- }
518
+ // VULNERABLE: Path traversal via join with user input
519
+ app.get('/document', (req, res) => {
520
+ const docName = req.query.doc as string;
521
+ const filePath = join('./documents', docName);
522
+ createReadStream(filePath).pipe(res);
523
+ });
493
524
 
494
- // SAFE: Basename extraction and validation
495
- export async function getFileSecure(filename: string) {
496
- const basename = require('path').basename(filename);
497
- const safePath = join('./uploads', basename);
498
- return readFile(safePath, 'utf-8');
499
- }
525
+ // SAFE: Fixed allowlist of known files, no user input in path
526
+ const ALLOWED_FILES: Record<string, string> = {
527
+ readme: './uploads/readme.txt',
528
+ license: './uploads/license.txt',
529
+ };
530
+ app.get('/upload', (req, res) => {
531
+ const key = req.query.name as string;
532
+ const safePath = ALLOWED_FILES[key];
533
+ if (!safePath) {
534
+ return res.status(404).send('Not found');
535
+ }
536
+ readFile(safePath, 'utf-8').then((content) => res.send(content));
537
+ });
500
538
  `,
501
539
  },
502
540
  ],
503
541
  expectedFindings: [
504
542
  {
505
543
  file: "files.ts",
506
- line: 6,
507
- severity: "high",
508
- category: "path-traversal",
509
- cweId: "CWE-22",
510
- description: "Path traversal via direct user input",
511
- isVulnerable: true,
512
- },
513
- {
514
- file: "files.ts",
515
- line: 12,
544
+ line: 17,
516
545
  severity: "high",
517
546
  category: "path-traversal",
518
547
  cweId: "CWE-22",
519
- description: "Path traversal via string concatenation",
548
+ description: "Path traversal via path.join with unvalidated request input",
520
549
  isVulnerable: true,
521
550
  },
522
551
  ],
@@ -537,25 +566,28 @@ export const commandInjectionFixtures = [
537
566
  {
538
567
  path: "utils/git.ts",
539
568
  language: "typescript",
540
- content: `import { exec } from 'child_process';
569
+ content: `import { exec, spawn } from 'child_process';
570
+ import express from 'express';
541
571
 
542
- // VULNERABLE: User input directly in exec
543
- export function cloneRepo(repoUrl: string) {
544
- exec(\`git clone \${repoUrl}\`);
545
- }
572
+ const app = express();
546
573
 
547
- // SAFE: Array-based spawn
548
- import { spawn } from 'child_process';
549
- export function cloneRepoSafe(repoUrl: string) {
550
- spawn('git', ['clone', repoUrl]);
551
- }
574
+ // VULNERABLE: request input concatenated into a shell command
575
+ app.get('/clone', (req, res) => {
576
+ const repoUrl = req.query.repo;
577
+ exec(\`git clone \${repoUrl}\`, (err) => res.sendStatus(err ? 500 : 200));
578
+ });
579
+
580
+ // SAFE: array-based spawn, no shell interpolation
581
+ app.get('/clone-safe', (req, res) => {
582
+ spawn('git', ['clone', String(req.query.repo)]);
583
+ });
552
584
  `,
553
585
  },
554
586
  ],
555
587
  expectedFindings: [
556
588
  {
557
589
  file: "utils/git.ts",
558
- line: 5,
590
+ line: 8,
559
591
  severity: "critical",
560
592
  category: "command-injection",
561
593
  cweId: "CWE-78",
@@ -567,36 +599,40 @@ export function cloneRepoSafe(repoUrl: string) {
567
599
  },
568
600
  {
569
601
  id: "cmd-002",
570
- name: "spawn with shell:true",
571
- description: "Command injection via spawn with shell option enabled",
602
+ name: "exec with request input",
603
+ description: "Command injection via child_process.exec with request input",
572
604
  category: "command-injection",
573
605
  source: "custom",
574
606
  files: [
575
607
  {
576
608
  path: "services/deploy.ts",
577
609
  language: "typescript",
578
- content: `import { spawn } from 'child_process';
610
+ content: `import { exec } from 'child_process';
611
+ import express from 'express';
579
612
 
580
- // VULNERABLE: shell: true with user input
581
- export function runScript(scriptName: string) {
582
- spawn(\`./scripts/\${scriptName}.sh\`, { shell: true });
583
- }
613
+ const app = express();
584
614
 
585
- // SAFE: No shell option
586
- export function runScriptSafe(scriptName: string) {
587
- spawn('./scripts/run.sh', [scriptName]);
588
- }
615
+ // VULNERABLE: request input flows into exec
616
+ app.post('/run', (req, res) => {
617
+ const scriptName = req.body.script;
618
+ exec('./scripts/' + scriptName + '.sh', (err) => res.sendStatus(err ? 500 : 200));
619
+ });
620
+
621
+ // SAFE: fixed command
622
+ app.post('/run-safe', (_req, res) => {
623
+ exec('./scripts/run.sh', () => res.sendStatus(200));
624
+ });
589
625
  `,
590
626
  },
591
627
  ],
592
628
  expectedFindings: [
593
629
  {
594
630
  file: "services/deploy.ts",
595
- line: 5,
631
+ line: 9,
596
632
  severity: "critical",
597
633
  category: "command-injection",
598
634
  cweId: "CWE-78",
599
- description: "shell: true enables command injection",
635
+ description: "Command injection via request input in exec",
600
636
  isVulnerable: true,
601
637
  },
602
638
  ],
@@ -617,28 +653,32 @@ export const ssrfFixtures = [
617
653
  {
618
654
  path: "api/proxy.ts",
619
655
  language: "typescript",
620
- content: `// VULNERABLE: Direct user URL in fetch
621
- export async function proxyRequest(url: string) {
622
- const response = await fetch(url);
623
- return response.json();
624
- }
656
+ content: `import express from 'express';
657
+
658
+ const app = express();
659
+
660
+ // VULNERABLE: request-controlled URL passed straight to fetch
661
+ app.get('/proxy', async (req, res) => {
662
+ const response = await fetch(req.query.url);
663
+ res.json(await response.json());
664
+ });
625
665
 
626
666
  // SAFE: URL allowlist
627
667
  const ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com'];
628
- export async function proxyRequestSafe(url: string) {
629
- const parsed = new URL(url);
668
+ app.get('/proxy-safe', async (req, res) => {
669
+ const parsed = new URL(String(req.query.url));
630
670
  if (!ALLOWED_HOSTS.includes(parsed.host)) {
631
- throw new Error('Host not allowed');
671
+ return res.status(400).end();
632
672
  }
633
- return fetch(url);
634
- }
673
+ res.json(await (await fetch('https://api.example.com')).json());
674
+ });
635
675
  `,
636
676
  },
637
677
  ],
638
678
  expectedFindings: [
639
679
  {
640
680
  file: "api/proxy.ts",
641
- line: 3,
681
+ line: 7,
642
682
  severity: "high",
643
683
  category: "ssrf",
644
684
  cweId: "CWE-918",
@@ -659,30 +699,32 @@ export async function proxyRequestSafe(url: string) {
659
699
  path: "services/webhook.ts",
660
700
  language: "typescript",
661
701
  content: `import axios from 'axios';
702
+ import express from 'express';
662
703
 
663
- // VULNERABLE: Following redirects to internal networks
664
- export async function callWebhook(webhookUrl: string, payload: object) {
665
- const response = await axios.post(webhookUrl, payload, {
666
- maxRedirects: 5, // Can redirect to internal networks
667
- });
668
- return response.data;
669
- }
704
+ const app = express();
670
705
 
671
- // SAFE: Validate URL and disable redirects
672
- export async function callWebhookSafe(webhookUrl: string, payload: object) {
673
- const url = new URL(webhookUrl);
706
+ // VULNERABLE: request-controlled webhook URL
707
+ app.post('/webhook', async (req, res) => {
708
+ const webhookUrl = req.body.url;
709
+ const response = await axios.post(webhookUrl, req.body.payload);
710
+ res.json(response.data);
711
+ });
712
+
713
+ // SAFE: validate URL against internal ranges first
714
+ app.post('/webhook-safe', async (req, res) => {
715
+ const url = new URL(String(req.body.url));
674
716
  if (url.hostname === 'localhost' || url.hostname.startsWith('192.168.')) {
675
- throw new Error('Internal URLs not allowed');
717
+ return res.status(400).end();
676
718
  }
677
- return axios.post(webhookUrl, payload, { maxRedirects: 0 });
678
- }
719
+ res.json((await axios.post('https://hooks.example.com', req.body.payload)).data);
720
+ });
679
721
  `,
680
722
  },
681
723
  ],
682
724
  expectedFindings: [
683
725
  {
684
726
  file: "services/webhook.ts",
685
- line: 5,
727
+ line: 9,
686
728
  severity: "high",
687
729
  category: "ssrf",
688
730
  cweId: "CWE-918",