@zivis/mcp 0.1.8 → 0.1.10

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 (330) 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/index.d.ts +0 -6
  20. package/dist/index.js +0 -7
  21. package/dist/lib/inspect-cache.d.ts +10 -0
  22. package/dist/lib/inspect-cache.js +75 -0
  23. package/dist/lib/next-steps.d.ts +27 -0
  24. package/dist/lib/next-steps.js +21 -0
  25. package/dist/matcher/ast-eval.d.ts +8 -0
  26. package/dist/matcher/ast-eval.js +95 -0
  27. package/dist/matcher/finding.d.ts +55 -0
  28. package/dist/matcher/finding.js +1 -0
  29. package/dist/matcher/index.d.ts +8 -0
  30. package/dist/matcher/index.js +202 -0
  31. package/dist/matcher/inference-candidates.d.ts +26 -0
  32. package/dist/matcher/inference-candidates.js +81 -0
  33. package/dist/matcher/walker.d.ts +7 -0
  34. package/dist/matcher/walker.js +71 -0
  35. package/dist/pattern-pack/index.d.ts +125 -0
  36. package/dist/pattern-pack/index.js +189 -0
  37. package/dist/pattern-packs/zivis-public-0.2.0/capsules/agents/privilege-separation.yaml +224 -0
  38. package/dist/pattern-packs/zivis-public-0.2.0/capsules/prompting/self-consistency-no-isolation.yaml +237 -0
  39. package/dist/pattern-packs/zivis-public-0.2.0/capsules/retrieval/context-injection-no-validator.yaml +348 -0
  40. package/dist/pattern-packs/zivis-public-0.2.0/capsules/security/late-org-filter.yaml +266 -0
  41. package/dist/pattern-packs/zivis-public-0.2.0/controls/external_validator_on_facts.yaml +37 -0
  42. package/dist/pattern-packs/zivis-public-0.2.0/controls/fact_validator_present.yaml +68 -0
  43. package/dist/pattern-packs/zivis-public-0.2.0/controls/human_approval_gate.yaml +44 -0
  44. package/dist/pattern-packs/zivis-public-0.2.0/controls/langgraph_state_machine_with_per_node_tools.yaml +35 -0
  45. package/dist/pattern-packs/zivis-public-0.2.0/controls/per_sample_retrieval_diversification.yaml +38 -0
  46. package/dist/pattern-packs/zivis-public-0.2.0/controls/prisma_extension_or_middleware_attaching_org_filter.yaml +31 -0
  47. package/dist/pattern-packs/zivis-public-0.2.0/controls/row_level_security_policy.yaml +37 -0
  48. package/dist/pattern-packs/zivis-public-0.2.0/controls/source_attribution_present.yaml +58 -0
  49. package/dist/pattern-packs/zivis-public-0.2.0/manifest.json +167 -0
  50. package/dist/pattern-packs/zivis-public-0.2.0/prompts/agents/privilege-separation/identify.md +54 -0
  51. package/dist/pattern-packs/zivis-public-0.2.0/prompts/prompting/self-consistency-no-isolation/identify.md +60 -0
  52. package/dist/pattern-packs/zivis-public-0.2.0/prompts/retrieval/context-injection-no-validator/identify.md +109 -0
  53. package/dist/pattern-packs/zivis-public-0.2.0/prompts/security/late-org-filter/identify.md +78 -0
  54. package/dist/project-binding.d.ts +2 -19
  55. package/dist/project-binding.js +38 -21
  56. package/dist/prompts/audit-dependencies.d.ts +2 -0
  57. package/dist/prompts/audit-dependencies.js +47 -0
  58. package/dist/prompts/getting-started.d.ts +2 -0
  59. package/dist/prompts/getting-started.js +37 -0
  60. package/dist/prompts/index.d.ts +2 -0
  61. package/dist/prompts/index.js +6 -0
  62. package/dist/resolve-application-id.d.ts +0 -4
  63. package/dist/resolve-application-id.js +0 -5
  64. package/dist/sanitize.d.ts +1 -21
  65. package/dist/sanitize.js +7 -41
  66. package/dist/server.d.ts +1 -13
  67. package/dist/server.js +142 -265
  68. package/dist/tools/artifacts.d.ts +76 -0
  69. package/dist/tools/artifacts.js +178 -0
  70. package/dist/tools/check-project.d.ts +5 -18
  71. package/dist/tools/check-project.js +122 -110
  72. package/dist/tools/check-repo-trust.d.ts +4 -19
  73. package/dist/tools/check-repo-trust.js +56 -47
  74. package/dist/tools/create-diagram.d.ts +0 -5
  75. package/dist/tools/create-diagram.js +0 -10
  76. package/dist/tools/create-document.d.ts +0 -5
  77. package/dist/tools/create-document.js +3 -9
  78. package/dist/tools/create-finding.d.ts +85 -0
  79. package/dist/tools/create-finding.js +136 -0
  80. package/dist/tools/delete-finding.d.ts +19 -0
  81. package/dist/tools/delete-finding.js +36 -0
  82. package/dist/tools/devx-run.d.ts +88 -0
  83. package/dist/tools/devx-run.js +175 -0
  84. package/dist/tools/discover-local-infra.d.ts +0 -10
  85. package/dist/tools/discover-local-infra.js +3 -73
  86. package/dist/tools/enterprise/get-org-zat.d.ts +0 -5
  87. package/dist/tools/enterprise/get-org-zat.js +0 -6
  88. package/dist/tools/explain-signal-for-diff.d.ts +34 -0
  89. package/dist/tools/explain-signal-for-diff.js +75 -0
  90. package/dist/tools/generate-diagram.d.ts +0 -6
  91. package/dist/tools/generate-diagram.js +21 -13
  92. package/dist/tools/get-application-overview.d.ts +0 -5
  93. package/dist/tools/get-application-overview.js +0 -6
  94. package/dist/tools/get-application.d.ts +0 -5
  95. package/dist/tools/get-application.js +0 -6
  96. package/dist/tools/get-diagram.d.ts +0 -5
  97. package/dist/tools/get-diagram.js +1 -11
  98. package/dist/tools/get-document.d.ts +0 -5
  99. package/dist/tools/get-document.js +0 -6
  100. package/dist/tools/get-oss-zat.d.ts +0 -5
  101. package/dist/tools/get-oss-zat.js +0 -7
  102. package/dist/tools/get-signal.d.ts +24 -0
  103. package/dist/tools/get-signal.js +75 -0
  104. package/dist/tools/get-started.d.ts +18 -0
  105. package/dist/tools/get-started.js +470 -0
  106. package/dist/tools/get-trust-keys.d.ts +0 -5
  107. package/dist/tools/get-trust-keys.js +0 -6
  108. package/dist/tools/import-openapi-endpoints.d.ts +0 -5
  109. package/dist/tools/import-openapi-endpoints.js +0 -6
  110. package/dist/tools/inspect-zat.d.ts +0 -5
  111. package/dist/tools/inspect-zat.js +0 -19
  112. package/dist/tools/inspect.d.ts +21 -0
  113. package/dist/tools/inspect.js +222 -0
  114. package/dist/tools/list-applications.d.ts +1 -6
  115. package/dist/tools/list-applications.js +0 -6
  116. package/dist/tools/list-diagrams.d.ts +0 -5
  117. package/dist/tools/list-diagrams.js +0 -6
  118. package/dist/tools/list-documents.d.ts +0 -5
  119. package/dist/tools/list-documents.js +0 -6
  120. package/dist/tools/list-endpoints.d.ts +1 -6
  121. package/dist/tools/list-endpoints.js +0 -6
  122. package/dist/tools/list-signals.d.ts +37 -0
  123. package/dist/tools/list-signals.js +83 -0
  124. package/dist/tools/manage-application.d.ts +64 -0
  125. package/dist/tools/manage-application.js +129 -0
  126. package/dist/tools/manage-diagram.d.ts +0 -5
  127. package/dist/tools/manage-diagram.js +0 -16
  128. package/dist/tools/manage-endpoint-lifecycle.d.ts +80 -0
  129. package/dist/tools/manage-endpoint-lifecycle.js +180 -0
  130. package/dist/tools/open-in-ide.d.ts +2 -14
  131. package/dist/tools/open-in-ide.js +0 -13
  132. package/dist/tools/review-change.d.ts +34 -0
  133. package/dist/tools/review-change.js +93 -0
  134. package/dist/tools/security-memory.d.ts +76 -0
  135. package/dist/tools/security-memory.js +202 -0
  136. package/dist/tools/security-review.d.ts +1 -21
  137. package/dist/tools/security-review.js +8 -108
  138. package/dist/tools/threat-get-capsule.d.ts +15 -0
  139. package/dist/tools/threat-get-capsule.js +53 -0
  140. package/dist/tools/threat-get-inference-prompt.d.ts +15 -0
  141. package/dist/tools/threat-get-inference-prompt.js +73 -0
  142. package/dist/tools/threat-list-relevant-capsules.d.ts +17 -0
  143. package/dist/tools/threat-list-relevant-capsules.js +158 -0
  144. package/dist/tools/threat-run-matcher.d.ts +17 -0
  145. package/dist/tools/threat-run-matcher.js +145 -0
  146. package/dist/tools/update-document.d.ts +0 -5
  147. package/dist/tools/update-document.js +3 -9
  148. package/dist/tools/update-endpoint.d.ts +1 -6
  149. package/dist/tools/update-endpoint.js +0 -7
  150. package/dist/tools/update-finding.d.ts +61 -0
  151. package/dist/tools/update-finding.js +80 -0
  152. package/dist/tools/update-mermaid-source.d.ts +0 -13
  153. package/dist/tools/update-mermaid-source.js +0 -14
  154. package/dist/tools/verify-trust-mark.d.ts +0 -5
  155. package/dist/tools/verify-trust-mark.js +0 -6
  156. package/dist/types.d.ts +14 -14
  157. package/dist/types.js +22 -28
  158. package/package.json +38 -15
  159. package/dist/api-client.js.map +0 -1
  160. package/dist/auth/index.js.map +0 -1
  161. package/dist/auth/jwt.js.map +0 -1
  162. package/dist/auth/keychain.js.map +0 -1
  163. package/dist/auth/oauth.js.map +0 -1
  164. package/dist/auth/sessions.js.map +0 -1
  165. package/dist/auth/token-refresh.js.map +0 -1
  166. package/dist/cli.js.map +0 -1
  167. package/dist/index.js.map +0 -1
  168. package/dist/project-binding.js.map +0 -1
  169. package/dist/resolve-application-id.js.map +0 -1
  170. package/dist/sanitize.js.map +0 -1
  171. package/dist/server.js.map +0 -1
  172. package/dist/tools/check-project.js.map +0 -1
  173. package/dist/tools/check-repo-trust.js.map +0 -1
  174. package/dist/tools/create-diagram.js.map +0 -1
  175. package/dist/tools/create-document.js.map +0 -1
  176. package/dist/tools/discover-local-infra.js.map +0 -1
  177. package/dist/tools/enterprise/capture-evidence.d.ts +0 -54
  178. package/dist/tools/enterprise/capture-evidence.js +0 -72
  179. package/dist/tools/enterprise/capture-evidence.js.map +0 -1
  180. package/dist/tools/enterprise/create-report-ticket.d.ts +0 -34
  181. package/dist/tools/enterprise/create-report-ticket.js +0 -44
  182. package/dist/tools/enterprise/create-report-ticket.js.map +0 -1
  183. package/dist/tools/enterprise/end-pentest-session.d.ts +0 -33
  184. package/dist/tools/enterprise/end-pentest-session.js +0 -42
  185. package/dist/tools/enterprise/end-pentest-session.js.map +0 -1
  186. package/dist/tools/enterprise/generate-report.d.ts +0 -55
  187. package/dist/tools/enterprise/generate-report.js +0 -111
  188. package/dist/tools/enterprise/generate-report.js.map +0 -1
  189. package/dist/tools/enterprise/get-org-zat.js.map +0 -1
  190. package/dist/tools/enterprise/get-report-status.d.ts +0 -27
  191. package/dist/tools/enterprise/get-report-status.js +0 -38
  192. package/dist/tools/enterprise/get-report-status.js.map +0 -1
  193. package/dist/tools/enterprise/get-threat-model.d.ts +0 -29
  194. package/dist/tools/enterprise/get-threat-model.js +0 -83
  195. package/dist/tools/enterprise/get-threat-model.js.map +0 -1
  196. package/dist/tools/enterprise/list-agents.d.ts +0 -42
  197. package/dist/tools/enterprise/list-agents.js +0 -95
  198. package/dist/tools/enterprise/list-agents.js.map +0 -1
  199. package/dist/tools/enterprise/list-report-issues.d.ts +0 -36
  200. package/dist/tools/enterprise/list-report-issues.js +0 -50
  201. package/dist/tools/enterprise/list-report-issues.js.map +0 -1
  202. package/dist/tools/enterprise/list-threat-models.d.ts +0 -36
  203. package/dist/tools/enterprise/list-threat-models.js +0 -82
  204. package/dist/tools/enterprise/list-threat-models.js.map +0 -1
  205. package/dist/tools/enterprise/manage-actor.d.ts +0 -58
  206. package/dist/tools/enterprise/manage-actor.js +0 -99
  207. package/dist/tools/enterprise/manage-actor.js.map +0 -1
  208. package/dist/tools/enterprise/manage-attack-scenario.d.ts +0 -70
  209. package/dist/tools/enterprise/manage-attack-scenario.js +0 -89
  210. package/dist/tools/enterprise/manage-attack-scenario.js.map +0 -1
  211. package/dist/tools/enterprise/manage-component.d.ts +0 -58
  212. package/dist/tools/enterprise/manage-component.js +0 -90
  213. package/dist/tools/enterprise/manage-component.js.map +0 -1
  214. package/dist/tools/enterprise/manage-data-asset.d.ts +0 -53
  215. package/dist/tools/enterprise/manage-data-asset.js +0 -90
  216. package/dist/tools/enterprise/manage-data-asset.js.map +0 -1
  217. package/dist/tools/enterprise/manage-data-flow.d.ts +0 -57
  218. package/dist/tools/enterprise/manage-data-flow.js +0 -98
  219. package/dist/tools/enterprise/manage-data-flow.js.map +0 -1
  220. package/dist/tools/enterprise/manage-finding.d.ts +0 -69
  221. package/dist/tools/enterprise/manage-finding.js +0 -106
  222. package/dist/tools/enterprise/manage-finding.js.map +0 -1
  223. package/dist/tools/enterprise/manage-security-control.d.ts +0 -59
  224. package/dist/tools/enterprise/manage-security-control.js +0 -96
  225. package/dist/tools/enterprise/manage-security-control.js.map +0 -1
  226. package/dist/tools/enterprise/manage-test-case.d.ts +0 -88
  227. package/dist/tools/enterprise/manage-test-case.js +0 -119
  228. package/dist/tools/enterprise/manage-test-case.js.map +0 -1
  229. package/dist/tools/enterprise/promote-finding-to-issue.d.ts +0 -36
  230. package/dist/tools/enterprise/promote-finding-to-issue.js +0 -65
  231. package/dist/tools/enterprise/promote-finding-to-issue.js.map +0 -1
  232. package/dist/tools/enterprise/publish-report-version.d.ts +0 -34
  233. package/dist/tools/enterprise/publish-report-version.js +0 -75
  234. package/dist/tools/enterprise/publish-report-version.js.map +0 -1
  235. package/dist/tools/enterprise/publish-test-to-library.d.ts +0 -31
  236. package/dist/tools/enterprise/publish-test-to-library.js +0 -40
  237. package/dist/tools/enterprise/publish-test-to-library.js.map +0 -1
  238. package/dist/tools/enterprise/record-test-result.d.ts +0 -67
  239. package/dist/tools/enterprise/record-test-result.js +0 -75
  240. package/dist/tools/enterprise/record-test-result.js.map +0 -1
  241. package/dist/tools/enterprise/start-pentest-session.d.ts +0 -35
  242. package/dist/tools/enterprise/start-pentest-session.js +0 -50
  243. package/dist/tools/enterprise/start-pentest-session.js.map +0 -1
  244. package/dist/tools/enterprise/sync-report-section.d.ts +0 -41
  245. package/dist/tools/enterprise/sync-report-section.js +0 -79
  246. package/dist/tools/enterprise/sync-report-section.js.map +0 -1
  247. package/dist/tools/enterprise/update-report-issue.d.ts +0 -55
  248. package/dist/tools/enterprise/update-report-issue.js +0 -69
  249. package/dist/tools/enterprise/update-report-issue.js.map +0 -1
  250. package/dist/tools/generate-diagram.js.map +0 -1
  251. package/dist/tools/get-agent-test-results.d.ts +0 -41
  252. package/dist/tools/get-agent-test-results.js +0 -86
  253. package/dist/tools/get-agent-test-results.js.map +0 -1
  254. package/dist/tools/get-application-overview.js.map +0 -1
  255. package/dist/tools/get-application.js.map +0 -1
  256. package/dist/tools/get-artifact-content.d.ts +0 -29
  257. package/dist/tools/get-artifact-content.js +0 -86
  258. package/dist/tools/get-artifact-content.js.map +0 -1
  259. package/dist/tools/get-diagram.js.map +0 -1
  260. package/dist/tools/get-document.js.map +0 -1
  261. package/dist/tools/get-finding-details.d.ts +0 -28
  262. package/dist/tools/get-finding-details.js +0 -43
  263. package/dist/tools/get-finding-details.js.map +0 -1
  264. package/dist/tools/get-findings.d.ts +0 -57
  265. package/dist/tools/get-findings.js +0 -103
  266. package/dist/tools/get-findings.js.map +0 -1
  267. package/dist/tools/get-oss-zat.js.map +0 -1
  268. package/dist/tools/get-recon-scan.d.ts +0 -27
  269. package/dist/tools/get-recon-scan.js +0 -46
  270. package/dist/tools/get-recon-scan.js.map +0 -1
  271. package/dist/tools/get-scan-output.d.ts +0 -27
  272. package/dist/tools/get-scan-output.js +0 -64
  273. package/dist/tools/get-scan-output.js.map +0 -1
  274. package/dist/tools/get-scenario-details.d.ts +0 -27
  275. package/dist/tools/get-scenario-details.js +0 -46
  276. package/dist/tools/get-scenario-details.js.map +0 -1
  277. package/dist/tools/get-test-case-results.d.ts +0 -37
  278. package/dist/tools/get-test-case-results.js +0 -66
  279. package/dist/tools/get-test-case-results.js.map +0 -1
  280. package/dist/tools/get-test-details.d.ts +0 -29
  281. package/dist/tools/get-test-details.js +0 -49
  282. package/dist/tools/get-test-details.js.map +0 -1
  283. package/dist/tools/get-trust-keys.js.map +0 -1
  284. package/dist/tools/import-openapi-endpoints.js.map +0 -1
  285. package/dist/tools/inspect-zat.js.map +0 -1
  286. package/dist/tools/list-agent-test-cases.d.ts +0 -41
  287. package/dist/tools/list-agent-test-cases.js +0 -73
  288. package/dist/tools/list-agent-test-cases.js.map +0 -1
  289. package/dist/tools/list-applications.js.map +0 -1
  290. package/dist/tools/list-diagrams.js.map +0 -1
  291. package/dist/tools/list-documents.js.map +0 -1
  292. package/dist/tools/list-endpoints.js.map +0 -1
  293. package/dist/tools/list-recon-scans.d.ts +0 -36
  294. package/dist/tools/list-recon-scans.js +0 -74
  295. package/dist/tools/list-recon-scans.js.map +0 -1
  296. package/dist/tools/list-scan-artifacts.d.ts +0 -41
  297. package/dist/tools/list-scan-artifacts.js +0 -63
  298. package/dist/tools/list-scan-artifacts.js.map +0 -1
  299. package/dist/tools/list-scans.d.ts +0 -44
  300. package/dist/tools/list-scans.js +0 -91
  301. package/dist/tools/list-scans.js.map +0 -1
  302. package/dist/tools/list-test-library.d.ts +0 -44
  303. package/dist/tools/list-test-library.js +0 -83
  304. package/dist/tools/list-test-library.js.map +0 -1
  305. package/dist/tools/list-test-scenarios.d.ts +0 -31
  306. package/dist/tools/list-test-scenarios.js +0 -66
  307. package/dist/tools/list-test-scenarios.js.map +0 -1
  308. package/dist/tools/local-scan.d.ts +0 -40
  309. package/dist/tools/local-scan.js +0 -261
  310. package/dist/tools/local-scan.js.map +0 -1
  311. package/dist/tools/manage-diagram.js.map +0 -1
  312. package/dist/tools/open-in-ide.js.map +0 -1
  313. package/dist/tools/run-test-scenario.d.ts +0 -37
  314. package/dist/tools/run-test-scenario.js +0 -70
  315. package/dist/tools/run-test-scenario.js.map +0 -1
  316. package/dist/tools/scan-pr.d.ts +0 -27
  317. package/dist/tools/scan-pr.js +0 -51
  318. package/dist/tools/scan-pr.js.map +0 -1
  319. package/dist/tools/security-review.js.map +0 -1
  320. package/dist/tools/setup-red-team-target.d.ts +0 -79
  321. package/dist/tools/setup-red-team-target.js +0 -430
  322. package/dist/tools/setup-red-team-target.js.map +0 -1
  323. package/dist/tools/triage-finding.d.ts +0 -47
  324. package/dist/tools/triage-finding.js +0 -116
  325. package/dist/tools/triage-finding.js.map +0 -1
  326. package/dist/tools/update-document.js.map +0 -1
  327. package/dist/tools/update-endpoint.js.map +0 -1
  328. package/dist/tools/update-mermaid-source.js.map +0 -1
  329. package/dist/tools/verify-trust-mark.js.map +0 -1
  330. package/dist/types.js.map +0 -1
@@ -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
@@ -0,0 +1,68 @@
1
+ # Control: fact_validator_present
2
+ # Referenced by:
3
+ # - retrieval.context-injection-no-validator (META: none_of_controls)
4
+ #
5
+ # A validator that inspects retrieved or LLM-generated content for
6
+ # prompt-injection patterns, factual inconsistency, or policy violations
7
+ # before the content reaches the model (or the user). Presence of any of
8
+ # the well-known guardrails libraries OR a custom validator with a
9
+ # recognizable name counts.
10
+
11
+ id: fact_validator_present
12
+ description: >
13
+ A validator step that inspects content for injection / hallucination /
14
+ policy violations between the data source (retriever, tool, user input)
15
+ and the model — or between the model and the user. Either a recognizable
16
+ third-party guardrails library or a custom validator with a clear name.
17
+
18
+ applicable_languages:
19
+ - typescript
20
+ - javascript
21
+ - python
22
+
23
+ detection:
24
+ - language: typescript
25
+ rule:
26
+ any:
27
+ # Third-party guardrails libraries (presence of the import or call)
28
+ - pattern: from "guardrails"
29
+ - pattern: from "@guardrails-ai/core"
30
+ - pattern: from "nemoguardrails"
31
+ - pattern: from "@nvidia/nemo-guardrails"
32
+ - pattern: from "lakera-guard"
33
+ - pattern: from "@lakera/guard"
34
+ - pattern: from "llm-guard"
35
+ - pattern: from "@protectai/llm-guard"
36
+ - pattern: from "presidio-analyzer"
37
+ # Conventional function names — broad on purpose so customer
38
+ # codebases register when they roll their own
39
+ - pattern: validateRetrievedContent($$$)
40
+ - pattern: validateContent($$$)
41
+ - pattern: factCheck($$$)
42
+ - pattern: checkForInjection($$$)
43
+ - pattern: sanitizeRetrieved($$$)
44
+ - pattern: detectPromptInjection($$$)
45
+ - pattern: $_.validate($DOCS)
46
+ - pattern: $_.guard($$$)
47
+ - language: python
48
+ rule:
49
+ any:
50
+ - pattern: import guardrails
51
+ - pattern: from guardrails import $$$
52
+ - pattern: import nemoguardrails
53
+ - pattern: from nemoguardrails import $$$
54
+ - pattern: import lakera_guard
55
+ - pattern: from lakera_guard import $$$
56
+ - pattern: import llm_guard
57
+ - pattern: from llm_guard import $$$
58
+ - pattern: from presidio_analyzer import $$$
59
+ # Conventional function names
60
+ - pattern: validate_retrieved_content($$$)
61
+ - pattern: validate_content($$$)
62
+ - pattern: fact_check($$$)
63
+ - pattern: check_for_injection($$$)
64
+ - pattern: sanitize_retrieved($$$)
65
+ - pattern: detect_prompt_injection($$$)
66
+
67
+ owner: platform-threat-modeling
68
+ lifecycle: draft
@@ -0,0 +1,44 @@
1
+ # Control: human_approval_gate
2
+ # Referenced by:
3
+ # - prompting.self-consistency-no-isolation (META: none_of_controls)
4
+ # - agents.privilege-separation (potential — high-impact tool dispatch)
5
+ #
6
+ # Defines what "the codebase has a human-in-the-loop approval before
7
+ # committing a high-impact action" looks like. Detection is intentionally
8
+ # fuzzy — we'd rather over-detect approval gates (and miss firing META)
9
+ # than under-detect (and fire false-positive findings).
10
+
11
+ id: human_approval_gate
12
+ description: >
13
+ Detects code that pauses execution to wait for human approval before
14
+ committing a high-impact action. Common shapes: humanInTheLoop helpers,
15
+ LangGraph interrupts, await-on-approval queue reads, request-confirmation
16
+ prompts.
17
+
18
+ applicable_languages:
19
+ - typescript
20
+ - javascript
21
+ - python
22
+
23
+ detection:
24
+ - language: typescript
25
+ rule:
26
+ any:
27
+ - pattern: humanInTheLoop($$$)
28
+ - pattern: humanApproval($$$)
29
+ - pattern: requireApproval($$$)
30
+ - pattern: await $_.waitForApproval($$$)
31
+ - pattern: await $_.awaitApproval($$$)
32
+ - pattern: $_.interrupt($$$)
33
+ - language: python
34
+ rule:
35
+ any:
36
+ - pattern: human_in_the_loop($$$)
37
+ - pattern: human_approval($$$)
38
+ - pattern: require_approval($$$)
39
+ - pattern: wait_for_user($$$)
40
+ - pattern: await_approval($$$)
41
+ - pattern: $_.interrupt($$$)
42
+
43
+ owner: platform-threat-modeling
44
+ lifecycle: draft
@@ -0,0 +1,35 @@
1
+ # Control: langgraph_state_machine_with_per_node_tools
2
+ # Referenced by:
3
+ # - agents.privilege-separation (META: none_of_controls)
4
+ #
5
+ # LangGraph's idiom for privilege separation: a StateGraph with multiple
6
+ # nodes, each binding a different (smaller) tool set. When present, the
7
+ # capsule's anti-pattern (one shared tool list) is mitigated.
8
+
9
+ id: langgraph_state_machine_with_per_node_tools
10
+ description: >
11
+ LangGraph StateGraph with multiple add_node calls — each node typically
12
+ binds its own tools. Even imperfect detection of LangGraph node-graph
13
+ construction is enough to suppress the capsule's META rule, since the
14
+ customer is clearly using the right idiom.
15
+
16
+ applicable_languages:
17
+ - typescript
18
+ - javascript
19
+ - python
20
+
21
+ detection:
22
+ - language: python
23
+ rule:
24
+ any:
25
+ - pattern: $_.add_node($$$)
26
+ - pattern: StateGraph($$$)
27
+ - pattern: builder.add_node($$$)
28
+ - language: typescript
29
+ rule:
30
+ any:
31
+ - pattern: $_.addNode($$$)
32
+ - pattern: new StateGraph($$$)
33
+
34
+ owner: platform-threat-modeling
35
+ lifecycle: draft
@@ -0,0 +1,38 @@
1
+ # Control: per_sample_retrieval_diversification
2
+ # Referenced by:
3
+ # - prompting.self-consistency-no-isolation (META: none_of_controls)
4
+ #
5
+ # Different samples in a self-consistency loop pull from different
6
+ # retrieval queries / different stores / different rerank seeds, instead
7
+ # of all sharing the same RAG context.
8
+
9
+ id: per_sample_retrieval_diversification
10
+ description: >
11
+ When a self-consistency aggregator pulls retrieval per-sample from
12
+ varied queries (i.e. retrieval is INSIDE the per-sample lambda, not
13
+ hoisted above the loop). The shape is a .map over generation function
14
+ that itself contains a similaritySearch / vectorStore call.
15
+
16
+ applicable_languages:
17
+ - typescript
18
+ - javascript
19
+ - python
20
+
21
+ detection:
22
+ - language: typescript
23
+ rule:
24
+ pattern: $_.similaritySearch($$$)
25
+ inside:
26
+ stopBy: end
27
+ any:
28
+ - pattern: $_.map($$$)
29
+ - kind: for_statement
30
+ - language: python
31
+ rule:
32
+ pattern: $_.similarity_search($$$)
33
+ inside:
34
+ stopBy: end
35
+ kind: for_statement
36
+
37
+ owner: platform-threat-modeling
38
+ lifecycle: draft
@@ -0,0 +1,31 @@
1
+ # Control: prisma_extension_or_middleware_attaching_org_filter
2
+ # Referenced by:
3
+ # - security.late-org-filter (META: none_of_controls)
4
+ #
5
+ # A Prisma extension (or legacy $use middleware) that automatically appends
6
+ # a where-clause scoping every query by org/tenant. When present, the
7
+ # late-filter pattern is defense in depth, not the primary control.
8
+
9
+ id: prisma_extension_or_middleware_attaching_org_filter
10
+ description: >
11
+ Prisma client extension (post-5.x) or legacy $use middleware that injects
12
+ org/tenant scoping into every query. Detected by the call shape that
13
+ registers the extension/middleware referencing org_id, orgId, or tenant_id.
14
+
15
+ applicable_languages:
16
+ - typescript
17
+ - javascript
18
+
19
+ detection:
20
+ - language: typescript
21
+ rule:
22
+ any:
23
+ # Modern Prisma client extension intercepting query operations
24
+ - pattern: "$_.$$extends({ query: $$$ })"
25
+ - pattern: "prisma.$$extends($$$)"
26
+ # Legacy Prisma middleware
27
+ - pattern: "$_.$$use($$$)"
28
+ - pattern: "prisma.$$use($$$)"
29
+
30
+ owner: platform-threat-modeling
31
+ lifecycle: draft
@@ -0,0 +1,37 @@
1
+ # Control: row_level_security_policy
2
+ # Referenced by:
3
+ # - security.late-org-filter (META: none_of_controls)
4
+ #
5
+ # Detection of Postgres RLS policies in the codebase — either authored as
6
+ # SQL migration text inside a string literal, or invoked via session GUC
7
+ # setters that scope the connection by tenant.
8
+
9
+ id: row_level_security_policy
10
+ description: >
11
+ Postgres row-level security policy authored in the codebase, or session
12
+ GUCs that scope a connection by tenant for the duration of a request.
13
+
14
+ applicable_languages:
15
+ - typescript
16
+ - javascript
17
+ - python
18
+
19
+ detection:
20
+ - language: typescript
21
+ rule:
22
+ any:
23
+ # SET LOCAL app.org_id pattern (per-request connection scoping)
24
+ - pattern: $_.$$queryRaw`SET LOCAL $$$`
25
+ - pattern: $_.$$executeRaw`SET LOCAL $$$`
26
+ # Common helpers
27
+ - pattern: setRlsContext($$$)
28
+ - pattern: setOrgContext($$$)
29
+ - language: python
30
+ rule:
31
+ any:
32
+ - pattern: $_.execute("SET LOCAL $$$")
33
+ - pattern: set_rls_context($$$)
34
+ - pattern: set_org_context($$$)
35
+
36
+ owner: platform-threat-modeling
37
+ lifecycle: draft
@@ -0,0 +1,58 @@
1
+ # Control: source_attribution_present
2
+ # Referenced by:
3
+ # - retrieval.context-injection-no-validator (META: none_of_controls)
4
+ #
5
+ # A pattern where retrieved documents carry source-identifier metadata
6
+ # the model is required to surface (citations) and / or the calling code
7
+ # uses to apply access control after retrieval. Either flavor counts —
8
+ # the point is that the corpus is not treated as an undifferentiated
9
+ # trusted blob.
10
+
11
+ id: source_attribution_present
12
+ description: >
13
+ Retrieved documents carry source-identifier metadata that flows into
14
+ the prompt as required citations, OR into a post-retrieval access /
15
+ trust filter. Presence of either flavor is treated as evidence that
16
+ the corpus is not being treated as an undifferentiated trusted blob.
17
+
18
+ applicable_languages:
19
+ - typescript
20
+ - javascript
21
+ - python
22
+
23
+ detection:
24
+ - language: typescript
25
+ rule:
26
+ any:
27
+ # Citation-style: doc IDs / sources embedded in prompt template
28
+ - pattern: $_.sourceId
29
+ - pattern: $_.source_id
30
+ - pattern: $_.citation
31
+ - pattern: $_.sourceUrl
32
+ - pattern: $_.documentId
33
+ # Post-retrieval access filter
34
+ - pattern: filterByAccess($$$)
35
+ - pattern: filterBySourceAccess($$$)
36
+ - pattern: filterRetrievedByPermission($$$)
37
+ - pattern: checkDocumentAccess($$$)
38
+ - pattern: assertSourceAllowed($$$)
39
+ # LangChain-style citation chains
40
+ - pattern: createCitationsChain($$$)
41
+ - pattern: new SourceAttributedRetrievalChain($$$)
42
+ - language: python
43
+ rule:
44
+ any:
45
+ - pattern: $_.source_id
46
+ - pattern: $_.citation
47
+ - pattern: $_.source_url
48
+ - pattern: $_.document_id
49
+ - pattern: filter_by_access($$$)
50
+ - pattern: filter_by_source_access($$$)
51
+ - pattern: filter_retrieved_by_permission($$$)
52
+ - pattern: check_document_access($$$)
53
+ - pattern: assert_source_allowed($$$)
54
+ # LangChain
55
+ - pattern: create_citations_chain($$$)
56
+
57
+ owner: platform-threat-modeling
58
+ lifecycle: draft