@zivis/mcp 0.1.8 → 0.1.11

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 (346) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +19 -0
  3. package/dist/api-client.d.ts +2 -24
  4. package/dist/api-client.js +32 -52
  5. package/dist/auth/index.d.ts +1 -22
  6. package/dist/auth/index.js +17 -38
  7. package/dist/auth/jwt.d.ts +0 -16
  8. package/dist/auth/jwt.js +0 -13
  9. package/dist/auth/keychain.d.ts +6 -32
  10. package/dist/auth/keychain.js +83 -114
  11. package/dist/auth/oauth.d.ts +3 -32
  12. package/dist/auth/oauth.js +67 -61
  13. package/dist/auth/sessions.d.ts +5 -25
  14. package/dist/auth/sessions.js +20 -39
  15. package/dist/auth/token-refresh.d.ts +2 -22
  16. package/dist/auth/token-refresh.js +33 -36
  17. package/dist/cli.d.ts +1 -18
  18. package/dist/cli.js +30 -908
  19. package/dist/http-probe/capture.d.ts +51 -0
  20. package/dist/http-probe/capture.js +96 -0
  21. package/dist/http-probe/compare.d.ts +43 -0
  22. package/dist/http-probe/compare.js +117 -0
  23. package/dist/http-probe/index.d.ts +2 -0
  24. package/dist/http-probe/index.js +2 -0
  25. package/dist/index.d.ts +0 -6
  26. package/dist/index.js +0 -7
  27. package/dist/lib/inspect-cache.d.ts +10 -0
  28. package/dist/lib/inspect-cache.js +75 -0
  29. package/dist/lib/next-steps.d.ts +27 -0
  30. package/dist/lib/next-steps.js +21 -0
  31. package/dist/matcher/ast-eval.d.ts +8 -0
  32. package/dist/matcher/ast-eval.js +95 -0
  33. package/dist/matcher/finding.d.ts +55 -0
  34. package/dist/matcher/finding.js +1 -0
  35. package/dist/matcher/index.d.ts +8 -0
  36. package/dist/matcher/index.js +202 -0
  37. package/dist/matcher/inference-candidates.d.ts +26 -0
  38. package/dist/matcher/inference-candidates.js +81 -0
  39. package/dist/matcher/walker.d.ts +7 -0
  40. package/dist/matcher/walker.js +71 -0
  41. package/dist/pattern-pack/index.d.ts +125 -0
  42. package/dist/pattern-pack/index.js +189 -0
  43. package/dist/pattern-packs/zivis-public-0.2.0/capsules/agents/privilege-separation.yaml +224 -0
  44. package/dist/pattern-packs/zivis-public-0.2.0/capsules/prompting/self-consistency-no-isolation.yaml +237 -0
  45. package/dist/pattern-packs/zivis-public-0.2.0/capsules/retrieval/context-injection-no-validator.yaml +348 -0
  46. package/dist/pattern-packs/zivis-public-0.2.0/capsules/security/late-org-filter.yaml +266 -0
  47. package/dist/pattern-packs/zivis-public-0.2.0/controls/external_validator_on_facts.yaml +37 -0
  48. package/dist/pattern-packs/zivis-public-0.2.0/controls/fact_validator_present.yaml +68 -0
  49. package/dist/pattern-packs/zivis-public-0.2.0/controls/human_approval_gate.yaml +44 -0
  50. package/dist/pattern-packs/zivis-public-0.2.0/controls/langgraph_state_machine_with_per_node_tools.yaml +35 -0
  51. package/dist/pattern-packs/zivis-public-0.2.0/controls/per_sample_retrieval_diversification.yaml +38 -0
  52. package/dist/pattern-packs/zivis-public-0.2.0/controls/prisma_extension_or_middleware_attaching_org_filter.yaml +31 -0
  53. package/dist/pattern-packs/zivis-public-0.2.0/controls/row_level_security_policy.yaml +37 -0
  54. package/dist/pattern-packs/zivis-public-0.2.0/controls/source_attribution_present.yaml +58 -0
  55. package/dist/pattern-packs/zivis-public-0.2.0/manifest.json +167 -0
  56. package/dist/pattern-packs/zivis-public-0.2.0/prompts/agents/privilege-separation/identify.md +54 -0
  57. package/dist/pattern-packs/zivis-public-0.2.0/prompts/prompting/self-consistency-no-isolation/identify.md +60 -0
  58. package/dist/pattern-packs/zivis-public-0.2.0/prompts/retrieval/context-injection-no-validator/identify.md +109 -0
  59. package/dist/pattern-packs/zivis-public-0.2.0/prompts/security/late-org-filter/identify.md +78 -0
  60. package/dist/project-binding.d.ts +2 -19
  61. package/dist/project-binding.js +38 -21
  62. package/dist/prompts/audit-dependencies.d.ts +2 -0
  63. package/dist/prompts/audit-dependencies.js +47 -0
  64. package/dist/prompts/getting-started.d.ts +2 -0
  65. package/dist/prompts/getting-started.js +37 -0
  66. package/dist/prompts/index.d.ts +2 -0
  67. package/dist/prompts/index.js +6 -0
  68. package/dist/redact.d.ts +30 -0
  69. package/dist/redact.js +164 -0
  70. package/dist/resolve-application-id.d.ts +0 -4
  71. package/dist/resolve-application-id.js +0 -5
  72. package/dist/sanitize.d.ts +1 -21
  73. package/dist/sanitize.js +7 -41
  74. package/dist/scanners/index.d.ts +3 -0
  75. package/dist/scanners/index.js +2 -0
  76. package/dist/scanners/normalize.d.ts +6 -0
  77. package/dist/scanners/normalize.js +181 -0
  78. package/dist/scanners/run.d.ts +27 -0
  79. package/dist/scanners/run.js +142 -0
  80. package/dist/scanners/types.d.ts +40 -0
  81. package/dist/scanners/types.js +1 -0
  82. package/dist/server.d.ts +1 -13
  83. package/dist/server.js +142 -265
  84. package/dist/tools/artifacts.d.ts +76 -0
  85. package/dist/tools/artifacts.js +178 -0
  86. package/dist/tools/check-project.d.ts +5 -18
  87. package/dist/tools/check-project.js +122 -110
  88. package/dist/tools/check-repo-trust.d.ts +4 -19
  89. package/dist/tools/check-repo-trust.js +56 -47
  90. package/dist/tools/create-diagram.d.ts +0 -5
  91. package/dist/tools/create-diagram.js +0 -10
  92. package/dist/tools/create-document.d.ts +0 -5
  93. package/dist/tools/create-document.js +3 -9
  94. package/dist/tools/create-finding.d.ts +85 -0
  95. package/dist/tools/create-finding.js +136 -0
  96. package/dist/tools/delete-finding.d.ts +19 -0
  97. package/dist/tools/delete-finding.js +36 -0
  98. package/dist/tools/devx-run.d.ts +88 -0
  99. package/dist/tools/devx-run.js +175 -0
  100. package/dist/tools/discover-local-infra.d.ts +0 -10
  101. package/dist/tools/discover-local-infra.js +3 -73
  102. package/dist/tools/enterprise/get-org-zat.d.ts +0 -5
  103. package/dist/tools/enterprise/get-org-zat.js +0 -6
  104. package/dist/tools/explain-signal-for-diff.d.ts +34 -0
  105. package/dist/tools/explain-signal-for-diff.js +75 -0
  106. package/dist/tools/generate-diagram.d.ts +0 -6
  107. package/dist/tools/generate-diagram.js +21 -13
  108. package/dist/tools/get-application-overview.d.ts +0 -5
  109. package/dist/tools/get-application-overview.js +0 -6
  110. package/dist/tools/get-application.d.ts +0 -5
  111. package/dist/tools/get-application.js +0 -6
  112. package/dist/tools/get-diagram.d.ts +0 -5
  113. package/dist/tools/get-diagram.js +1 -11
  114. package/dist/tools/get-document.d.ts +0 -5
  115. package/dist/tools/get-document.js +0 -6
  116. package/dist/tools/get-oss-zat.d.ts +0 -5
  117. package/dist/tools/get-oss-zat.js +0 -7
  118. package/dist/tools/get-signal.d.ts +24 -0
  119. package/dist/tools/get-signal.js +75 -0
  120. package/dist/tools/get-started.d.ts +18 -0
  121. package/dist/tools/get-started.js +470 -0
  122. package/dist/tools/get-trust-keys.d.ts +0 -5
  123. package/dist/tools/get-trust-keys.js +0 -6
  124. package/dist/tools/import-openapi-endpoints.d.ts +0 -5
  125. package/dist/tools/import-openapi-endpoints.js +0 -6
  126. package/dist/tools/inspect-zat.d.ts +0 -5
  127. package/dist/tools/inspect-zat.js +0 -19
  128. package/dist/tools/inspect.d.ts +21 -0
  129. package/dist/tools/inspect.js +222 -0
  130. package/dist/tools/list-applications.d.ts +1 -6
  131. package/dist/tools/list-applications.js +0 -6
  132. package/dist/tools/list-diagrams.d.ts +0 -5
  133. package/dist/tools/list-diagrams.js +0 -6
  134. package/dist/tools/list-documents.d.ts +0 -5
  135. package/dist/tools/list-documents.js +0 -6
  136. package/dist/tools/list-endpoints.d.ts +1 -6
  137. package/dist/tools/list-endpoints.js +0 -6
  138. package/dist/tools/list-signals.d.ts +37 -0
  139. package/dist/tools/list-signals.js +83 -0
  140. package/dist/tools/manage-application.d.ts +64 -0
  141. package/dist/tools/manage-application.js +129 -0
  142. package/dist/tools/manage-diagram.d.ts +0 -5
  143. package/dist/tools/manage-diagram.js +0 -16
  144. package/dist/tools/manage-endpoint-lifecycle.d.ts +80 -0
  145. package/dist/tools/manage-endpoint-lifecycle.js +180 -0
  146. package/dist/tools/open-in-ide.d.ts +2 -14
  147. package/dist/tools/open-in-ide.js +0 -13
  148. package/dist/tools/review-change.d.ts +34 -0
  149. package/dist/tools/review-change.js +93 -0
  150. package/dist/tools/security-memory.d.ts +76 -0
  151. package/dist/tools/security-memory.js +202 -0
  152. package/dist/tools/security-review.d.ts +1 -21
  153. package/dist/tools/security-review.js +8 -108
  154. package/dist/tools/threat-get-capsule.d.ts +15 -0
  155. package/dist/tools/threat-get-capsule.js +53 -0
  156. package/dist/tools/threat-get-inference-prompt.d.ts +15 -0
  157. package/dist/tools/threat-get-inference-prompt.js +73 -0
  158. package/dist/tools/threat-list-relevant-capsules.d.ts +17 -0
  159. package/dist/tools/threat-list-relevant-capsules.js +158 -0
  160. package/dist/tools/threat-run-matcher.d.ts +17 -0
  161. package/dist/tools/threat-run-matcher.js +145 -0
  162. package/dist/tools/update-document.d.ts +0 -5
  163. package/dist/tools/update-document.js +3 -9
  164. package/dist/tools/update-endpoint.d.ts +1 -6
  165. package/dist/tools/update-endpoint.js +0 -7
  166. package/dist/tools/update-finding.d.ts +61 -0
  167. package/dist/tools/update-finding.js +80 -0
  168. package/dist/tools/update-mermaid-source.d.ts +0 -13
  169. package/dist/tools/update-mermaid-source.js +0 -14
  170. package/dist/tools/verify-trust-mark.d.ts +0 -5
  171. package/dist/tools/verify-trust-mark.js +0 -6
  172. package/dist/types.d.ts +14 -14
  173. package/dist/types.js +22 -28
  174. package/package.json +41 -15
  175. package/dist/api-client.js.map +0 -1
  176. package/dist/auth/index.js.map +0 -1
  177. package/dist/auth/jwt.js.map +0 -1
  178. package/dist/auth/keychain.js.map +0 -1
  179. package/dist/auth/oauth.js.map +0 -1
  180. package/dist/auth/sessions.js.map +0 -1
  181. package/dist/auth/token-refresh.js.map +0 -1
  182. package/dist/cli.js.map +0 -1
  183. package/dist/index.js.map +0 -1
  184. package/dist/project-binding.js.map +0 -1
  185. package/dist/resolve-application-id.js.map +0 -1
  186. package/dist/sanitize.js.map +0 -1
  187. package/dist/server.js.map +0 -1
  188. package/dist/tools/check-project.js.map +0 -1
  189. package/dist/tools/check-repo-trust.js.map +0 -1
  190. package/dist/tools/create-diagram.js.map +0 -1
  191. package/dist/tools/create-document.js.map +0 -1
  192. package/dist/tools/discover-local-infra.js.map +0 -1
  193. package/dist/tools/enterprise/capture-evidence.d.ts +0 -54
  194. package/dist/tools/enterprise/capture-evidence.js +0 -72
  195. package/dist/tools/enterprise/capture-evidence.js.map +0 -1
  196. package/dist/tools/enterprise/create-report-ticket.d.ts +0 -34
  197. package/dist/tools/enterprise/create-report-ticket.js +0 -44
  198. package/dist/tools/enterprise/create-report-ticket.js.map +0 -1
  199. package/dist/tools/enterprise/end-pentest-session.d.ts +0 -33
  200. package/dist/tools/enterprise/end-pentest-session.js +0 -42
  201. package/dist/tools/enterprise/end-pentest-session.js.map +0 -1
  202. package/dist/tools/enterprise/generate-report.d.ts +0 -55
  203. package/dist/tools/enterprise/generate-report.js +0 -111
  204. package/dist/tools/enterprise/generate-report.js.map +0 -1
  205. package/dist/tools/enterprise/get-org-zat.js.map +0 -1
  206. package/dist/tools/enterprise/get-report-status.d.ts +0 -27
  207. package/dist/tools/enterprise/get-report-status.js +0 -38
  208. package/dist/tools/enterprise/get-report-status.js.map +0 -1
  209. package/dist/tools/enterprise/get-threat-model.d.ts +0 -29
  210. package/dist/tools/enterprise/get-threat-model.js +0 -83
  211. package/dist/tools/enterprise/get-threat-model.js.map +0 -1
  212. package/dist/tools/enterprise/list-agents.d.ts +0 -42
  213. package/dist/tools/enterprise/list-agents.js +0 -95
  214. package/dist/tools/enterprise/list-agents.js.map +0 -1
  215. package/dist/tools/enterprise/list-report-issues.d.ts +0 -36
  216. package/dist/tools/enterprise/list-report-issues.js +0 -50
  217. package/dist/tools/enterprise/list-report-issues.js.map +0 -1
  218. package/dist/tools/enterprise/list-threat-models.d.ts +0 -36
  219. package/dist/tools/enterprise/list-threat-models.js +0 -82
  220. package/dist/tools/enterprise/list-threat-models.js.map +0 -1
  221. package/dist/tools/enterprise/manage-actor.d.ts +0 -58
  222. package/dist/tools/enterprise/manage-actor.js +0 -99
  223. package/dist/tools/enterprise/manage-actor.js.map +0 -1
  224. package/dist/tools/enterprise/manage-attack-scenario.d.ts +0 -70
  225. package/dist/tools/enterprise/manage-attack-scenario.js +0 -89
  226. package/dist/tools/enterprise/manage-attack-scenario.js.map +0 -1
  227. package/dist/tools/enterprise/manage-component.d.ts +0 -58
  228. package/dist/tools/enterprise/manage-component.js +0 -90
  229. package/dist/tools/enterprise/manage-component.js.map +0 -1
  230. package/dist/tools/enterprise/manage-data-asset.d.ts +0 -53
  231. package/dist/tools/enterprise/manage-data-asset.js +0 -90
  232. package/dist/tools/enterprise/manage-data-asset.js.map +0 -1
  233. package/dist/tools/enterprise/manage-data-flow.d.ts +0 -57
  234. package/dist/tools/enterprise/manage-data-flow.js +0 -98
  235. package/dist/tools/enterprise/manage-data-flow.js.map +0 -1
  236. package/dist/tools/enterprise/manage-finding.d.ts +0 -69
  237. package/dist/tools/enterprise/manage-finding.js +0 -106
  238. package/dist/tools/enterprise/manage-finding.js.map +0 -1
  239. package/dist/tools/enterprise/manage-security-control.d.ts +0 -59
  240. package/dist/tools/enterprise/manage-security-control.js +0 -96
  241. package/dist/tools/enterprise/manage-security-control.js.map +0 -1
  242. package/dist/tools/enterprise/manage-test-case.d.ts +0 -88
  243. package/dist/tools/enterprise/manage-test-case.js +0 -119
  244. package/dist/tools/enterprise/manage-test-case.js.map +0 -1
  245. package/dist/tools/enterprise/promote-finding-to-issue.d.ts +0 -36
  246. package/dist/tools/enterprise/promote-finding-to-issue.js +0 -65
  247. package/dist/tools/enterprise/promote-finding-to-issue.js.map +0 -1
  248. package/dist/tools/enterprise/publish-report-version.d.ts +0 -34
  249. package/dist/tools/enterprise/publish-report-version.js +0 -75
  250. package/dist/tools/enterprise/publish-report-version.js.map +0 -1
  251. package/dist/tools/enterprise/publish-test-to-library.d.ts +0 -31
  252. package/dist/tools/enterprise/publish-test-to-library.js +0 -40
  253. package/dist/tools/enterprise/publish-test-to-library.js.map +0 -1
  254. package/dist/tools/enterprise/record-test-result.d.ts +0 -67
  255. package/dist/tools/enterprise/record-test-result.js +0 -75
  256. package/dist/tools/enterprise/record-test-result.js.map +0 -1
  257. package/dist/tools/enterprise/start-pentest-session.d.ts +0 -35
  258. package/dist/tools/enterprise/start-pentest-session.js +0 -50
  259. package/dist/tools/enterprise/start-pentest-session.js.map +0 -1
  260. package/dist/tools/enterprise/sync-report-section.d.ts +0 -41
  261. package/dist/tools/enterprise/sync-report-section.js +0 -79
  262. package/dist/tools/enterprise/sync-report-section.js.map +0 -1
  263. package/dist/tools/enterprise/update-report-issue.d.ts +0 -55
  264. package/dist/tools/enterprise/update-report-issue.js +0 -69
  265. package/dist/tools/enterprise/update-report-issue.js.map +0 -1
  266. package/dist/tools/generate-diagram.js.map +0 -1
  267. package/dist/tools/get-agent-test-results.d.ts +0 -41
  268. package/dist/tools/get-agent-test-results.js +0 -86
  269. package/dist/tools/get-agent-test-results.js.map +0 -1
  270. package/dist/tools/get-application-overview.js.map +0 -1
  271. package/dist/tools/get-application.js.map +0 -1
  272. package/dist/tools/get-artifact-content.d.ts +0 -29
  273. package/dist/tools/get-artifact-content.js +0 -86
  274. package/dist/tools/get-artifact-content.js.map +0 -1
  275. package/dist/tools/get-diagram.js.map +0 -1
  276. package/dist/tools/get-document.js.map +0 -1
  277. package/dist/tools/get-finding-details.d.ts +0 -28
  278. package/dist/tools/get-finding-details.js +0 -43
  279. package/dist/tools/get-finding-details.js.map +0 -1
  280. package/dist/tools/get-findings.d.ts +0 -57
  281. package/dist/tools/get-findings.js +0 -103
  282. package/dist/tools/get-findings.js.map +0 -1
  283. package/dist/tools/get-oss-zat.js.map +0 -1
  284. package/dist/tools/get-recon-scan.d.ts +0 -27
  285. package/dist/tools/get-recon-scan.js +0 -46
  286. package/dist/tools/get-recon-scan.js.map +0 -1
  287. package/dist/tools/get-scan-output.d.ts +0 -27
  288. package/dist/tools/get-scan-output.js +0 -64
  289. package/dist/tools/get-scan-output.js.map +0 -1
  290. package/dist/tools/get-scenario-details.d.ts +0 -27
  291. package/dist/tools/get-scenario-details.js +0 -46
  292. package/dist/tools/get-scenario-details.js.map +0 -1
  293. package/dist/tools/get-test-case-results.d.ts +0 -37
  294. package/dist/tools/get-test-case-results.js +0 -66
  295. package/dist/tools/get-test-case-results.js.map +0 -1
  296. package/dist/tools/get-test-details.d.ts +0 -29
  297. package/dist/tools/get-test-details.js +0 -49
  298. package/dist/tools/get-test-details.js.map +0 -1
  299. package/dist/tools/get-trust-keys.js.map +0 -1
  300. package/dist/tools/import-openapi-endpoints.js.map +0 -1
  301. package/dist/tools/inspect-zat.js.map +0 -1
  302. package/dist/tools/list-agent-test-cases.d.ts +0 -41
  303. package/dist/tools/list-agent-test-cases.js +0 -73
  304. package/dist/tools/list-agent-test-cases.js.map +0 -1
  305. package/dist/tools/list-applications.js.map +0 -1
  306. package/dist/tools/list-diagrams.js.map +0 -1
  307. package/dist/tools/list-documents.js.map +0 -1
  308. package/dist/tools/list-endpoints.js.map +0 -1
  309. package/dist/tools/list-recon-scans.d.ts +0 -36
  310. package/dist/tools/list-recon-scans.js +0 -74
  311. package/dist/tools/list-recon-scans.js.map +0 -1
  312. package/dist/tools/list-scan-artifacts.d.ts +0 -41
  313. package/dist/tools/list-scan-artifacts.js +0 -63
  314. package/dist/tools/list-scan-artifacts.js.map +0 -1
  315. package/dist/tools/list-scans.d.ts +0 -44
  316. package/dist/tools/list-scans.js +0 -91
  317. package/dist/tools/list-scans.js.map +0 -1
  318. package/dist/tools/list-test-library.d.ts +0 -44
  319. package/dist/tools/list-test-library.js +0 -83
  320. package/dist/tools/list-test-library.js.map +0 -1
  321. package/dist/tools/list-test-scenarios.d.ts +0 -31
  322. package/dist/tools/list-test-scenarios.js +0 -66
  323. package/dist/tools/list-test-scenarios.js.map +0 -1
  324. package/dist/tools/local-scan.d.ts +0 -40
  325. package/dist/tools/local-scan.js +0 -261
  326. package/dist/tools/local-scan.js.map +0 -1
  327. package/dist/tools/manage-diagram.js.map +0 -1
  328. package/dist/tools/open-in-ide.js.map +0 -1
  329. package/dist/tools/run-test-scenario.d.ts +0 -37
  330. package/dist/tools/run-test-scenario.js +0 -70
  331. package/dist/tools/run-test-scenario.js.map +0 -1
  332. package/dist/tools/scan-pr.d.ts +0 -27
  333. package/dist/tools/scan-pr.js +0 -51
  334. package/dist/tools/scan-pr.js.map +0 -1
  335. package/dist/tools/security-review.js.map +0 -1
  336. package/dist/tools/setup-red-team-target.d.ts +0 -79
  337. package/dist/tools/setup-red-team-target.js +0 -430
  338. package/dist/tools/setup-red-team-target.js.map +0 -1
  339. package/dist/tools/triage-finding.d.ts +0 -47
  340. package/dist/tools/triage-finding.js +0 -116
  341. package/dist/tools/triage-finding.js.map +0 -1
  342. package/dist/tools/update-document.js.map +0 -1
  343. package/dist/tools/update-endpoint.js.map +0 -1
  344. package/dist/tools/update-mermaid-source.js.map +0 -1
  345. package/dist/tools/verify-trust-mark.js.map +0 -1
  346. package/dist/types.js.map +0 -1
@@ -0,0 +1,348 @@
1
+ # Capsule: RAG context injection — retrieved content reaches the model without validation
2
+ # Spec: docs/specs/PATTERN-MATCHING-LIBRARY-V1.md
3
+ # Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md
4
+ # Schema: schemas/pattern-detection-card.schema.json
5
+
6
+ id: retrieval.context-injection-no-validator
7
+ slug: context-injection-no-validator
8
+ version: 0.1.0
9
+ category: retrieval
10
+ title: Retrieval Context Injection — No Validator Between Retriever and Model
11
+ headline: Retrieved Content Flows Into the LLM With Nothing Inspecting It First
12
+
13
+ description: >
14
+ Detects retrieval-augmented generation (RAG) flows where the output of a
15
+ retriever (vector store, search index, document loader) is passed directly
16
+ into the model call with no fact-validator, source-attribution check, or
17
+ content sanitizer in between. Retrieval becomes a transparent injection
18
+ channel: anyone who can write to the knowledge base — directly, via a
19
+ scraping job, or via a tool the agent itself calls — can steer the model.
20
+
21
+ detection_tier: public
22
+ scoring_tier: proprietary
23
+
24
+ applicable_languages:
25
+ - typescript
26
+ - javascript
27
+ - python
28
+
29
+ relevance_filter:
30
+ any_of:
31
+ # LangChain / LlamaIndex RAG stacks
32
+ - dependency: langchain
33
+ direct_only: true
34
+ - dependency: "@langchain/core"
35
+ direct_only: true
36
+ - dependency: "@langchain/openai"
37
+ direct_only: true
38
+ - dependency: "@langchain/anthropic"
39
+ direct_only: true
40
+ - dependency: "@langchain/community"
41
+ direct_only: true
42
+ - dependency: llamaindex
43
+ direct_only: true
44
+ - dependency: "llama-index"
45
+ direct_only: true
46
+ # Manual RAG: any LLM SDK + a vector store / retrieval client
47
+ - dependency: openai
48
+ direct_only: true
49
+ - dependency: "@anthropic-ai/sdk"
50
+ direct_only: true
51
+ - dependency: anthropic
52
+ direct_only: true
53
+ - dependency: "@pinecone-database/pinecone"
54
+ direct_only: true
55
+ - dependency: pinecone-client
56
+ direct_only: true
57
+ - dependency: "@qdrant/js-client-rest"
58
+ direct_only: true
59
+ - dependency: qdrant-client
60
+ direct_only: true
61
+ - dependency: weaviate-ts-client
62
+ direct_only: true
63
+ - dependency: weaviate-client
64
+ direct_only: true
65
+ - dependency: chromadb
66
+ direct_only: true
67
+ - dependency: "@elastic/elasticsearch"
68
+ direct_only: true
69
+ - dependency: elasticsearch
70
+
71
+ strategies:
72
+ # AST as architectural evidence (NOT a vulnerability claim) — does this
73
+ # codebase even have a retrieval→LLM call shape? If it doesn't, the
74
+ # pattern can't apply.
75
+ - code: AST
76
+ language: typescript
77
+ expression: |
78
+ rule:
79
+ any:
80
+ # LangChain idioms
81
+ - pattern: $RETRIEVER.invoke($$$)
82
+ - pattern: $RETRIEVER.getRelevantDocuments($$$)
83
+ - pattern: new RetrievalQAChain($$$)
84
+ - pattern: RetrievalQAChain.fromLLM($$$)
85
+ - pattern: createRetrievalChain($$$)
86
+ # LlamaIndex
87
+ - pattern: $INDEX.asQueryEngine($$$)
88
+ - pattern: $QUERY_ENGINE.query($$$)
89
+ # Manual RAG: vector-store similarity search feeding a model call
90
+ - pattern: $STORE.similaritySearch($$$)
91
+ - pattern: $STORE.similaritySearchWithScore($$$)
92
+ evidence_fields: [file_path, line_span, symbol]
93
+ confidence_weight: 0.40
94
+
95
+ - code: AST
96
+ language: python
97
+ expression: |
98
+ rule:
99
+ any:
100
+ # LangChain
101
+ - pattern: $RETRIEVER.invoke($$$)
102
+ - pattern: $RETRIEVER.get_relevant_documents($$$)
103
+ - pattern: RetrievalQA.from_chain_type($$$)
104
+ - pattern: create_retrieval_chain($$$)
105
+ # LlamaIndex
106
+ - pattern: $INDEX.as_query_engine($$$)
107
+ - pattern: $QUERY_ENGINE.query($$$)
108
+ # Manual RAG: vector-store similarity search
109
+ - pattern: $STORE.similarity_search($$$)
110
+ - pattern: $STORE.similarity_search_with_score($$$)
111
+ evidence_fields: [file_path, line_span, symbol]
112
+ confidence_weight: 0.40
113
+
114
+ # GRAPH strategy — forward-compatible. Matcher v1 doesn't evaluate
115
+ # graph predicates yet (per Phase 3 v1 in LOCAL-REPO-GRAPH-IMPLEMENTATION),
116
+ # but writing it now means the card "lights up" when the matcher catches
117
+ # up, without re-authoring.
118
+ - code: GRAPH
119
+ expression: |
120
+ retrieval_node_returns_documents
121
+ AND llm_call_node_consumes_documents
122
+ AND NO_NODE_BETWEEN(retrieval_node, llm_call_node) matches
123
+ (validator | fact_checker | source_attribution | content_sanitizer)
124
+ evidence_fields: [graph_path, file_spans, node_ids]
125
+ confidence_weight: 0.30
126
+
127
+ # META — does the codebase declare any of the controls that would make
128
+ # this pattern safe? Absence is what we care about.
129
+ - code: META
130
+ expression:
131
+ none_of_controls:
132
+ - fact_validator_present
133
+ - source_attribution_present
134
+ evidence_fields: [missing_controls]
135
+ confidence_weight: 0.30
136
+
137
+ # INFER — the host LLM (Claude in the IDE) gets the actual source spans
138
+ # and decides whether what looks like RAG truly has no validator. This is
139
+ # the lane we want most matches to land in: ZIVIS surfaces the candidate,
140
+ # the frontier model validates against the code.
141
+ - code: INFER
142
+ expression: prompt_id:retrieval.context-injection-no-validator.identify
143
+ evidence_fields: [llm_rationale]
144
+ confidence_weight: 0.20
145
+ trusted: false
146
+
147
+ # Two deterministic strategies must fire for a trusted-lane match. AST
148
+ # alone won't promote — it's just "there is RAG-shaped code." AST + META
149
+ # (controls absent) WILL promote. GRAPH lights up later for free.
150
+ required_evidence_count: 2
151
+
152
+ control_negations:
153
+ - "presence_of(fact_validator_present)"
154
+ - "presence_of(source_attribution_present)"
155
+
156
+ threats:
157
+ - title: Indirect prompt injection via retrieved corpus
158
+ stride: [tampering, elevation_of_privilege]
159
+ description: >
160
+ An attacker who can write to the retrieval corpus — a public web page
161
+ indexed by a scraper, a Confluence space synced into the vector store,
162
+ a customer-uploaded document, or a tool the agent uses to fetch
163
+ content — embeds instructions that the model treats as authoritative
164
+ because they arrive inside the "trusted" retrieval channel. The model
165
+ executes those instructions or leaks data based on them. With no
166
+ validator inspecting the retrieved text, the system has no defense
167
+ between the corpus and the model.
168
+ remediation: >
169
+ Insert a validation step between retriever and model that (a) checks
170
+ retrieved content for prompt-injection patterns, (b) requires
171
+ source-attribution metadata before content can influence answers, and
172
+ (c) rate-limits or content-flags low-trust sources. Patterns like
173
+ guardrails-ai, NeMo Guardrails, Lakera Guard, or a custom
174
+ `validateRetrievedContent()` boundary are all valid; the requirement
175
+ is that *some* boundary exists between corpus and model.
176
+
177
+ - title: Sensitive-data exfiltration via crafted retrieval queries
178
+ stride: [information_disclosure]
179
+ description: >
180
+ An attacker who can influence the retrieval query — directly or via a
181
+ preceding LLM step that re-writes the query — pulls documents the
182
+ requesting user should not see (other tenants' data, internal-only
183
+ pages indexed by mistake, PII-laden support tickets). The model then
184
+ surfaces that content in the response. Without source-attribution and
185
+ access checks at the retrieval boundary, the model becomes an
186
+ authorization bypass.
187
+ remediation: >
188
+ Enforce access control at the retrieval layer, not just at the API
189
+ layer. Tag every indexed document with the access scope it inherits
190
+ from its source system, and filter retrieval by the requesting
191
+ user's scope before content reaches the model. Treat the retriever
192
+ as a privileged data path — same scrutiny as any other query.
193
+
194
+ - title: Long-running drift from poisoned corpus
195
+ stride: [tampering, repudiation]
196
+ description: >
197
+ A single poisoned document indexed months ago continues to surface in
198
+ relevant queries indefinitely. The model's behavior drifts in ways
199
+ that are hard to attribute to a specific bug because the cause is in
200
+ the corpus, not the code. With no audit log of which retrieved
201
+ documents influenced which responses, post-incident investigation
202
+ cannot trace bad behavior back to its source.
203
+ remediation: >
204
+ Log every retrieval — query, returned document IDs, document hashes,
205
+ source attribution — alongside the LLM call it fed. Periodically
206
+ revalidate corpus contents against current trust assumptions
207
+ (re-classify documents from sources that have been compromised or
208
+ whose access policy changed).
209
+
210
+ fixtures:
211
+ positive:
212
+ - "fixtures/positive/context-injection-no-validator/langchain_rag_chain_no_validator_typescript"
213
+ - "fixtures/positive/context-injection-no-validator/llamaindex_query_engine_no_validator_python"
214
+ - "fixtures/positive/context-injection-no-validator/manual_pinecone_to_openai_typescript"
215
+ negative:
216
+ - "fixtures/negative/context-injection-no-validator/guardrails_validator_present_python"
217
+ - "fixtures/negative/context-injection-no-validator/source_attribution_check_typescript"
218
+
219
+ lifecycle: draft
220
+ owner: platform-threat-modeling
221
+ tags:
222
+ - retrieval
223
+ - rag
224
+ - prompt-injection
225
+ - context-injection
226
+ - corpus-poisoning
227
+ - agentic-ai
228
+
229
+ sensitivity_level: customer_safe
230
+ allowed_execution_modes:
231
+ - local_only
232
+ - local_model
233
+ - hybrid_cloud_eval
234
+
235
+ safe_summary: >
236
+ The codebase has a retrieval-augmented generation (RAG) shape — content
237
+ is pulled from a vector store, search index, or document loader and
238
+ passed to the LLM — but there's no validator, sanitizer, or
239
+ source-attribution check between the retriever and the model. Anyone
240
+ who can write to the retrieval corpus can steer the model: an indexed
241
+ web page, a synced Confluence space, a customer-uploaded document, or
242
+ a tool the agent itself fetches from. The fix is to put a boundary
243
+ between corpus and model — a guardrails library, a custom validator,
244
+ or per-document source-attribution that the model is required to
245
+ surface in its answers.
246
+
247
+ detect_when: >
248
+ A retriever call (`retriever.invoke`, `similaritySearch`, query engine,
249
+ retrieval chain) is followed by an LLM call within the same handler or
250
+ function, and the path between them contains no recognizable validator
251
+ or source-attribution step. Most common in chat / Q&A / "ask the docs"
252
+ applications.
253
+
254
+ risk_hints:
255
+ - "Retrieval is a privileged data path — anything in the corpus is implicitly trusted by the model"
256
+ - "Prompt injection embedded in a web page or shared doc survives indefinitely until the document is re-indexed"
257
+ - "Query rewriting (HyDE, multi-query) compounds the problem — the rewritten query is itself an LLM output"
258
+ - "Access control at the API layer doesn't help if the retriever pulls from a corpus indexed under different rules"
259
+ - "Logging the LLM input/output without logging the retrieved documents leaves the actual injection invisible"
260
+
261
+ architectural_signals:
262
+ - "Retriever / vector store / search index call returns documents"
263
+ - "Documents are concatenated into a system or user prompt slot"
264
+ - "No intermediate function whose name suggests validation, sanitization, or fact-checking"
265
+ - "No source-attribution requirement in the prompt template"
266
+
267
+ model_task_prompt_ref: prompts/retrieval/context-injection-no-validator/identify.md
268
+
269
+ expected_output_schema:
270
+ type: object
271
+ required: [verdict, validator_location, evidence_spans]
272
+ properties:
273
+ verdict:
274
+ type: string
275
+ enum: [no_validator_present, validator_present, partial_validator, unclear]
276
+ validator_location:
277
+ type: string
278
+ enum: [pre_retrieval, between_retriever_and_model, post_model, none, multiple]
279
+ rationale:
280
+ type: string
281
+ corpus_sources:
282
+ type: array
283
+ description: "Best-effort enumeration of where the retrieved content comes from"
284
+ items:
285
+ type: string
286
+ blast_radius:
287
+ type: string
288
+ enum: [single_endpoint, route_family, service_wide, agent_wide, unclear]
289
+ recommended_controls:
290
+ type: array
291
+ items:
292
+ type: string
293
+ enum:
294
+ - guardrails_library
295
+ - custom_content_validator
296
+ - source_attribution_in_prompt
297
+ - per_document_access_control
298
+ - retrieval_audit_log
299
+ - none
300
+ evidence_spans:
301
+ type: array
302
+ items:
303
+ type: object
304
+ required: [file]
305
+ properties:
306
+ file: { type: string }
307
+ start_line: { type: integer }
308
+ end_line: { type: integer }
309
+ note: { type: string }
310
+
311
+ minimum_context_required:
312
+ lines: 120
313
+ symbols:
314
+ - retriever
315
+ - invoke
316
+ - similarity_search
317
+ - similaritySearch
318
+ - query_engine
319
+ - asQueryEngine
320
+ - RetrievalQA
321
+ - create_retrieval_chain
322
+
323
+ related_patterns:
324
+ - prompting.user-input-in-system-prompt
325
+ - agents.tool-dispatch-from-llm-output
326
+
327
+ repair_contract:
328
+ allowed:
329
+ - "Insert a validator step between retriever and model call"
330
+ - "Add source-attribution requirement to the prompt template"
331
+ - "Adopt guardrails-ai / NeMo Guardrails / Lakera Guard or equivalent"
332
+ - "Implement per-document access control at the retrieval boundary"
333
+ - "Add structured logging of retrieved-document IDs alongside LLM calls"
334
+ forbidden:
335
+ - "Removing retrieval entirely without first replacing the answering path"
336
+ - "Validating only LLM output instead of retrieved content (treats the wrong stage)"
337
+ - "Hand-rolling regex injection filters as the sole defense (well-known to be bypassable)"
338
+
339
+ validation_contract:
340
+ requires_tests_pass: false
341
+ requires_static_rules:
342
+ - validator_node_present_between_retrieval_and_llm
343
+ - retrieval_audit_log_present
344
+
345
+ unsafe_to_expose_fields:
346
+ - internal_rubric
347
+ - golden_transcripts
348
+ - exploit_templates
@@ -0,0 +1,266 @@
1
+ # Capsule: Late org-filter — cross-tenant leak via presentation-time scoping
2
+ # Spec: docs/specs/PATTERN-MATCHING-LIBRARY-V1.md
3
+ # Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md
4
+ # Schema: schemas/pattern-detection-card.schema.json
5
+
6
+ id: security.late-org-filter
7
+ slug: late-org-filter
8
+ version: 0.1.0
9
+ category: security
10
+ title: Late Org Filter
11
+ headline: Tenant Scoping Applied After the Query, Not Inside It
12
+ description: >
13
+ Detects multi-tenant code paths where org/tenant filtering happens at the
14
+ presentation layer (response loop, stream emit, response shaping) instead
15
+ of inside the data query. Any race, error path, or partial response that
16
+ reaches the wire before the filter fires leaks rows across tenants.
17
+
18
+ detection_tier: public
19
+ scoring_tier: proprietary
20
+
21
+ applicable_languages:
22
+ - typescript
23
+ - javascript
24
+ - python
25
+ - go
26
+
27
+ relevance_filter:
28
+ any_of:
29
+ - dependency: express
30
+ direct_only: true
31
+ - dependency: fastify
32
+ direct_only: true
33
+ - dependency: hono
34
+ direct_only: true
35
+ - dependency: "@nestjs/core"
36
+ direct_only: true
37
+ - dependency: fastapi
38
+ direct_only: true
39
+ - dependency: flask
40
+ direct_only: true
41
+ - dependency: "django"
42
+ direct_only: true
43
+ - dependency: "github.com/gin-gonic/gin"
44
+ direct_only: true
45
+ - dependency: "github.com/labstack/echo/v4"
46
+ direct_only: true
47
+ none_of:
48
+ # If the project clearly isn't multi-tenant, skip — no benefit, lots of noise.
49
+ - evidence: "single_tenant_only_marker"
50
+
51
+ strategies:
52
+ - code: AST
53
+ language: typescript
54
+ expression: |
55
+ rule:
56
+ any:
57
+ # Filter applied to a query result then sent — classic shape.
58
+ - pattern: $ROWS.filter($_ => $_.orgId === $$$)
59
+ - pattern: $ROWS.filter($_ => $_.org_id === $$$)
60
+ - pattern: $ROWS.filter($_ => $_.tenantId === $$$)
61
+ # Per-row tenant guard inside a loop — the SSE / iterator variant.
62
+ - pattern: |
63
+ if ($R.orgId === $$$) {
64
+ $$$
65
+ }
66
+ - pattern: |
67
+ if ($R.org_id === $$$) {
68
+ $$$
69
+ }
70
+ evidence_fields: [file_path, line_span, symbol]
71
+ confidence_weight: 0.35
72
+
73
+ - code: AST
74
+ language: python
75
+ expression: |
76
+ rule:
77
+ any:
78
+ - pattern: |
79
+ rows = $QUERY($$$)
80
+ filtered = [r for r in rows if r.org_id == $REQ.org_id]
81
+ - pattern: |
82
+ for row in $QUERY($$$):
83
+ if row.org_id == request.org_id:
84
+ yield row
85
+ evidence_fields: [file_path, line_span, symbol]
86
+ confidence_weight: 0.35
87
+
88
+ - code: GRAPH
89
+ expression: |
90
+ query_call_returns_rows
91
+ AND filter_predicate_references(req_org_id OR session_org_id)
92
+ AND filter_executes_AFTER(query_call) IN response_handler_or_stream_emit
93
+ AND query_call.where_clause DOES_NOT include org_id
94
+ evidence_fields: [graph_path, file_spans, node_ids]
95
+ confidence_weight: 0.30
96
+
97
+ - code: META
98
+ expression:
99
+ none_of_controls:
100
+ - row_level_security_policy
101
+ - prisma_extension_or_middleware_attaching_org_filter
102
+ evidence_fields: [missing_controls]
103
+ confidence_weight: 0.20
104
+
105
+ - code: INFER
106
+ expression: prompt_id:security.late-org-filter.identify
107
+ evidence_fields: [llm_rationale]
108
+ confidence_weight: 0.15
109
+ trusted: false
110
+
111
+ required_evidence_count: 2
112
+
113
+ control_negations:
114
+ - "presence_of(row_level_security_policy)"
115
+ - "presence_of(query_helper_with_implicit_org_scope)"
116
+ - "presence_of(prisma_extension_or_middleware_attaching_org_filter)"
117
+
118
+ threats:
119
+ - title: Cross-tenant data leak via SSE / stream pre-filter window
120
+ stride: [information_disclosure, elevation_of_privilege]
121
+ description: >
122
+ In a streaming or async-iterator response, the underlying query returns
123
+ rows from all tenants and the per-emit filter rejects mismatches. A
124
+ brief window where rows are buffered, logged, traced, or partially
125
+ rendered before the filter executes can leak data across tenants. This
126
+ is the SSE / queue/stream variant of the pattern.
127
+ remediation: >
128
+ Push the org/tenant predicate into the data layer — RLS, query helpers,
129
+ ORM middleware. Make every query mandatorily org-scoped at the boundary;
130
+ treat presentation-layer filters as defense in depth, never the primary
131
+ barrier.
132
+ - title: Cross-tenant leak via error path or partial response
133
+ stride: [information_disclosure]
134
+ description: >
135
+ An exception inside the post-query filter loop returns the unfiltered
136
+ buffer or a serialization mid-state. Other tenants' rows reach the
137
+ wire because the only org check sits past the failure point.
138
+ remediation: >
139
+ Same control — RLS or query-time scoping. Plus: serialize the response
140
+ body only after filtering completes; on filter error, return a
141
+ structured error with no payload.
142
+ - title: Logged or traced rows expose other tenants
143
+ stride: [information_disclosure, repudiation]
144
+ description: >
145
+ Observability hooks (request logger, tracer, metrics) often capture the
146
+ raw query result before the presentation-layer filter runs. Other
147
+ tenants' identifiers, names, or PII land in logs the requesting tenant
148
+ should never have seen.
149
+ remediation: >
150
+ Either log only post-filter results, or — better — make the query
151
+ itself org-scoped so the unfiltered result never exists.
152
+
153
+ fixtures:
154
+ positive:
155
+ - "fixtures/positive/late-org-filter/express_sse_post_filter_typescript"
156
+ - "fixtures/positive/late-org-filter/fastapi_iterator_post_filter_python"
157
+ negative:
158
+ - "fixtures/negative/late-org-filter/prisma_middleware_org_scope"
159
+ - "fixtures/negative/late-org-filter/postgres_rls_enabled"
160
+
161
+ lifecycle: draft
162
+ owner: platform-threat-modeling
163
+ tags:
164
+ - multi-tenant
165
+ - cross-tenant-leak
166
+ - data-scoping
167
+ - sse
168
+ - stream
169
+
170
+ sensitivity_level: customer_safe
171
+ allowed_execution_modes:
172
+ - local_only
173
+ - local_model
174
+ - hybrid_cloud_eval
175
+
176
+ safe_summary: >
177
+ Tenant filtering applied after the query — at the response loop, the SSE
178
+ emit, or the stream iterator — instead of inside the query. Any error,
179
+ race, observability hook, or partial response that fires before the filter
180
+ reaches the wire leaks rows across tenants. The fix is to push org/tenant
181
+ scoping down to the data layer (RLS, query helpers, ORM middleware) so the
182
+ unfiltered set never exists in the first place.
183
+
184
+ detect_when: >
185
+ A handler, stream, or async iterator runs a data query, then filters the
186
+ result by `request.orgId` (or a session org) before responding — and the
187
+ query itself doesn't include the org predicate. Multi-tenant routes only.
188
+
189
+ risk_hints:
190
+ - The bug class behind a meaningful share of cross-tenant SaaS incidents
191
+ - SSE / queue / WebSocket variants are the hardest to spot because the filter looks "inside" the loop
192
+ - Logs and traces often capture the unfiltered set even when the response itself is clean
193
+ - Tests often pass because they only run with a single tenant in the test database
194
+
195
+ architectural_signals:
196
+ - Query call followed by an explicit filter referencing a request/session org id
197
+ - SSE or async iterator that yields events conditional on a tenant match
198
+ - No row-level security policy, no implicit-org-scope helper, no ORM middleware
199
+
200
+ model_task_prompt_ref: prompts/security/late-org-filter/identify.md
201
+
202
+ expected_output_schema:
203
+ type: object
204
+ required: [verdict, scope_location, evidence_spans]
205
+ properties:
206
+ verdict:
207
+ type: string
208
+ enum: [late_filter_present, scoped_at_query, partial_scope, unclear]
209
+ scope_location:
210
+ type: string
211
+ enum: [data_layer, query_layer, presentation_layer, multiple, none]
212
+ rationale:
213
+ type: string
214
+ blast_radius:
215
+ type: string
216
+ enum: [single_endpoint, route_family, service_wide, unclear]
217
+ recommended_controls:
218
+ type: array
219
+ items:
220
+ type: string
221
+ enum: [row_level_security, query_helper, orm_middleware, repository_pattern_with_org_scope, none]
222
+ evidence_spans:
223
+ type: array
224
+ items:
225
+ type: object
226
+ required: [file]
227
+ properties:
228
+ file: { type: string }
229
+ start_line: { type: integer }
230
+ end_line: { type: integer }
231
+ note: { type: string }
232
+
233
+ minimum_context_required:
234
+ lines: 100
235
+ symbols:
236
+ - orgId
237
+ - org_id
238
+ - tenant_id
239
+ - filter
240
+ - SSE
241
+ - stream
242
+
243
+ related_patterns:
244
+ - security.idor-via-direct-id
245
+ - security.broken-object-level-authz
246
+
247
+ repair_contract:
248
+ allowed:
249
+ - Push org/tenant scoping into the query (where clause, RLS, ORM middleware)
250
+ - Introduce a repository wrapper that mandates org_id on every method
251
+ - Add a Postgres row-level security policy
252
+ - Keep the presentation-layer filter as defense in depth IN ADDITION TO the data-layer scope
253
+ forbidden:
254
+ - Removing the presentation-layer filter without first introducing a data-layer scope (regresses safety)
255
+ - Treating the patch as complete after only fixing the immediate route — the bug class is structural
256
+
257
+ validation_contract:
258
+ requires_tests_pass: false
259
+ requires_static_rules:
260
+ - data_layer_org_scope_present_after_patch
261
+ - no_unscoped_query_remains_in_route_handler
262
+
263
+ unsafe_to_expose_fields:
264
+ - internal_rubric
265
+ - golden_transcripts
266
+ - exploit_templates
@@ -0,0 +1,37 @@
1
+ # Control: external_validator_on_facts
2
+ # Referenced by:
3
+ # - prompting.self-consistency-no-isolation (META: none_of_controls)
4
+ #
5
+ # An external (non-LLM) check that the aggregated answer is factually
6
+ # consistent — a SQL query, an API call, a regex against ground truth, etc.
7
+
8
+ id: external_validator_on_facts
9
+ description: >
10
+ An external, non-LLM check applied to the aggregated answer before it's
11
+ acted on. Common shapes: factCheck()/validateFacts() helpers, schema
12
+ validation, lookup against a trusted store.
13
+
14
+ applicable_languages:
15
+ - typescript
16
+ - javascript
17
+ - python
18
+
19
+ detection:
20
+ - language: typescript
21
+ rule:
22
+ any:
23
+ - pattern: factCheck($$$)
24
+ - pattern: validateFacts($$$)
25
+ - pattern: validateAnswer($$$)
26
+ - pattern: $_.factCheck($$$)
27
+ - pattern: $_.validate($$$)
28
+ - language: python
29
+ rule:
30
+ any:
31
+ - pattern: fact_check($$$)
32
+ - pattern: validate_facts($$$)
33
+ - pattern: validate_answer($$$)
34
+ - pattern: $_.validate_against_ground_truth($$$)
35
+
36
+ owner: platform-threat-modeling
37
+ lifecycle: draft