@zivis/mcp 0.1.0-alpha.21 → 0.1.0-alpha.22

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 (175) hide show
  1. package/dist/pattern-pack/index.d.ts +133 -0
  2. package/dist/pattern-pack/index.js +212 -0
  3. package/dist/pattern-pack/index.js.map +1 -0
  4. package/dist/pattern-packs/zivis-public-0.1.0/capsules/agents/privilege-separation.yaml +228 -0
  5. package/dist/pattern-packs/zivis-public-0.1.0/capsules/prompting/self-consistency-no-isolation.yaml +240 -0
  6. package/dist/pattern-packs/zivis-public-0.1.0/capsules/security/late-org-filter.yaml +270 -0
  7. package/dist/pattern-packs/zivis-public-0.1.0/manifest.json +68 -0
  8. package/dist/pattern-packs/zivis-public-0.1.0/prompts/agents/privilege-separation/identify.md +54 -0
  9. package/dist/pattern-packs/zivis-public-0.1.0/prompts/prompting/self-consistency-no-isolation/identify.md +60 -0
  10. package/dist/pattern-packs/zivis-public-0.1.0/prompts/security/late-org-filter/identify.md +78 -0
  11. package/dist/prompts/index.d.ts +1 -1
  12. package/dist/prompts/index.js +1 -7
  13. package/dist/prompts/index.js.map +1 -1
  14. package/dist/server.js +26 -166
  15. package/dist/server.js.map +1 -1
  16. package/dist/tools/enterprise/get-threat-model-artifact.d.ts +30 -0
  17. package/dist/tools/enterprise/get-threat-model-artifact.js +80 -0
  18. package/dist/tools/enterprise/get-threat-model-artifact.js.map +1 -0
  19. package/dist/tools/enterprise/get-threat-model.d.ts +1 -1
  20. package/dist/tools/enterprise/get-threat-model.js +59 -11
  21. package/dist/tools/enterprise/get-threat-model.js.map +1 -1
  22. package/dist/tools/enterprise/list-threat-model-artifacts.d.ts +67 -0
  23. package/dist/tools/enterprise/list-threat-model-artifacts.js +121 -0
  24. package/dist/tools/enterprise/list-threat-model-artifacts.js.map +1 -0
  25. package/dist/tools/enterprise/manage-data-asset.d.ts +1 -1
  26. package/dist/tools/enterprise/manage-data-flow.d.ts +1 -1
  27. package/dist/tools/enterprise/manage-test-case.d.ts +1 -1
  28. package/dist/tools/inspect.d.ts +31 -0
  29. package/dist/tools/inspect.js +100 -0
  30. package/dist/tools/inspect.js.map +1 -0
  31. package/dist/tools/manage-application.d.ts +1 -1
  32. package/dist/tools/security-review.js +67 -50
  33. package/dist/tools/security-review.js.map +1 -1
  34. package/dist/tools/threat-get-capsule.d.ts +25 -0
  35. package/dist/tools/threat-get-capsule.js +64 -0
  36. package/dist/tools/threat-get-capsule.js.map +1 -0
  37. package/dist/tools/threat-get-inference-prompt.d.ts +32 -0
  38. package/dist/tools/threat-get-inference-prompt.js +91 -0
  39. package/dist/tools/threat-get-inference-prompt.js.map +1 -0
  40. package/dist/tools/threat-list-relevant-capsules.d.ts +30 -0
  41. package/dist/tools/threat-list-relevant-capsules.js +176 -0
  42. package/dist/tools/threat-list-relevant-capsules.js.map +1 -0
  43. package/package.json +10 -3
  44. package/dist/prompts/prep-for-launch.d.ts +0 -9
  45. package/dist/prompts/prep-for-launch.js +0 -62
  46. package/dist/prompts/prep-for-launch.js.map +0 -1
  47. package/dist/prompts/secure-my-app.d.ts +0 -9
  48. package/dist/prompts/secure-my-app.js +0 -70
  49. package/dist/prompts/secure-my-app.js.map +0 -1
  50. package/dist/prompts/weekly-check.d.ts +0 -9
  51. package/dist/prompts/weekly-check.js +0 -48
  52. package/dist/prompts/weekly-check.js.map +0 -1
  53. package/dist/tools/enterprise/capture-evidence.d.ts +0 -54
  54. package/dist/tools/enterprise/capture-evidence.js +0 -72
  55. package/dist/tools/enterprise/capture-evidence.js.map +0 -1
  56. package/dist/tools/enterprise/create-report-ticket.d.ts +0 -34
  57. package/dist/tools/enterprise/create-report-ticket.js +0 -44
  58. package/dist/tools/enterprise/create-report-ticket.js.map +0 -1
  59. package/dist/tools/enterprise/end-pentest-session.d.ts +0 -33
  60. package/dist/tools/enterprise/end-pentest-session.js +0 -42
  61. package/dist/tools/enterprise/end-pentest-session.js.map +0 -1
  62. package/dist/tools/enterprise/generate-report.d.ts +0 -55
  63. package/dist/tools/enterprise/generate-report.js +0 -111
  64. package/dist/tools/enterprise/generate-report.js.map +0 -1
  65. package/dist/tools/enterprise/get-campaign.d.ts +0 -27
  66. package/dist/tools/enterprise/get-campaign.js +0 -31
  67. package/dist/tools/enterprise/get-campaign.js.map +0 -1
  68. package/dist/tools/enterprise/get-report-status.d.ts +0 -27
  69. package/dist/tools/enterprise/get-report-status.js +0 -38
  70. package/dist/tools/enterprise/get-report-status.js.map +0 -1
  71. package/dist/tools/enterprise/list-agents.d.ts +0 -42
  72. package/dist/tools/enterprise/list-agents.js +0 -95
  73. package/dist/tools/enterprise/list-agents.js.map +0 -1
  74. package/dist/tools/enterprise/list-campaigns.d.ts +0 -37
  75. package/dist/tools/enterprise/list-campaigns.js +0 -60
  76. package/dist/tools/enterprise/list-campaigns.js.map +0 -1
  77. package/dist/tools/enterprise/list-report-issues.d.ts +0 -36
  78. package/dist/tools/enterprise/list-report-issues.js +0 -50
  79. package/dist/tools/enterprise/list-report-issues.js.map +0 -1
  80. package/dist/tools/enterprise/manage-campaign-agent-instance.d.ts +0 -42
  81. package/dist/tools/enterprise/manage-campaign-agent-instance.js +0 -68
  82. package/dist/tools/enterprise/manage-campaign-agent-instance.js.map +0 -1
  83. package/dist/tools/enterprise/manage-campaign-target.d.ts +0 -44
  84. package/dist/tools/enterprise/manage-campaign-target.js +0 -70
  85. package/dist/tools/enterprise/manage-campaign-target.js.map +0 -1
  86. package/dist/tools/enterprise/manage-campaign.d.ts +0 -62
  87. package/dist/tools/enterprise/manage-campaign.js +0 -114
  88. package/dist/tools/enterprise/manage-campaign.js.map +0 -1
  89. package/dist/tools/enterprise/manage-finding.d.ts +0 -69
  90. package/dist/tools/enterprise/manage-finding.js +0 -106
  91. package/dist/tools/enterprise/manage-finding.js.map +0 -1
  92. package/dist/tools/enterprise/promote-finding-to-issue.d.ts +0 -36
  93. package/dist/tools/enterprise/promote-finding-to-issue.js +0 -65
  94. package/dist/tools/enterprise/promote-finding-to-issue.js.map +0 -1
  95. package/dist/tools/enterprise/publish-report-version.d.ts +0 -34
  96. package/dist/tools/enterprise/publish-report-version.js +0 -75
  97. package/dist/tools/enterprise/publish-report-version.js.map +0 -1
  98. package/dist/tools/enterprise/publish-test-to-library.d.ts +0 -31
  99. package/dist/tools/enterprise/publish-test-to-library.js +0 -40
  100. package/dist/tools/enterprise/publish-test-to-library.js.map +0 -1
  101. package/dist/tools/enterprise/record-test-result.d.ts +0 -67
  102. package/dist/tools/enterprise/record-test-result.js +0 -75
  103. package/dist/tools/enterprise/record-test-result.js.map +0 -1
  104. package/dist/tools/enterprise/start-pentest-session.d.ts +0 -35
  105. package/dist/tools/enterprise/start-pentest-session.js +0 -50
  106. package/dist/tools/enterprise/start-pentest-session.js.map +0 -1
  107. package/dist/tools/enterprise/sync-report-section.d.ts +0 -41
  108. package/dist/tools/enterprise/sync-report-section.js +0 -79
  109. package/dist/tools/enterprise/sync-report-section.js.map +0 -1
  110. package/dist/tools/enterprise/update-report-issue.d.ts +0 -55
  111. package/dist/tools/enterprise/update-report-issue.js +0 -69
  112. package/dist/tools/enterprise/update-report-issue.js.map +0 -1
  113. package/dist/tools/get-agent-test-results.d.ts +0 -41
  114. package/dist/tools/get-agent-test-results.js +0 -86
  115. package/dist/tools/get-agent-test-results.js.map +0 -1
  116. package/dist/tools/get-application-auth-config.d.ts +0 -27
  117. package/dist/tools/get-application-auth-config.js +0 -44
  118. package/dist/tools/get-application-auth-config.js.map +0 -1
  119. package/dist/tools/get-artifact-content.d.ts +0 -29
  120. package/dist/tools/get-artifact-content.js +0 -86
  121. package/dist/tools/get-artifact-content.js.map +0 -1
  122. package/dist/tools/get-finding-details.d.ts +0 -22
  123. package/dist/tools/get-finding-details.js +0 -61
  124. package/dist/tools/get-finding-details.js.map +0 -1
  125. package/dist/tools/get-findings.d.ts +0 -51
  126. package/dist/tools/get-findings.js +0 -124
  127. package/dist/tools/get-findings.js.map +0 -1
  128. package/dist/tools/get-recon-scan.d.ts +0 -27
  129. package/dist/tools/get-recon-scan.js +0 -46
  130. package/dist/tools/get-recon-scan.js.map +0 -1
  131. package/dist/tools/get-scan-output.d.ts +0 -27
  132. package/dist/tools/get-scan-output.js +0 -64
  133. package/dist/tools/get-scan-output.js.map +0 -1
  134. package/dist/tools/get-scenario-details.d.ts +0 -27
  135. package/dist/tools/get-scenario-details.js +0 -46
  136. package/dist/tools/get-scenario-details.js.map +0 -1
  137. package/dist/tools/get-test-case-results.d.ts +0 -37
  138. package/dist/tools/get-test-case-results.js +0 -66
  139. package/dist/tools/get-test-case-results.js.map +0 -1
  140. package/dist/tools/get-test-details.d.ts +0 -29
  141. package/dist/tools/get-test-details.js +0 -49
  142. package/dist/tools/get-test-details.js.map +0 -1
  143. package/dist/tools/list-agent-test-cases.d.ts +0 -41
  144. package/dist/tools/list-agent-test-cases.js +0 -73
  145. package/dist/tools/list-agent-test-cases.js.map +0 -1
  146. package/dist/tools/list-recon-scans.d.ts +0 -36
  147. package/dist/tools/list-recon-scans.js +0 -74
  148. package/dist/tools/list-recon-scans.js.map +0 -1
  149. package/dist/tools/list-scan-artifacts.d.ts +0 -41
  150. package/dist/tools/list-scan-artifacts.js +0 -63
  151. package/dist/tools/list-scan-artifacts.js.map +0 -1
  152. package/dist/tools/list-scans.d.ts +0 -38
  153. package/dist/tools/list-scans.js +0 -125
  154. package/dist/tools/list-scans.js.map +0 -1
  155. package/dist/tools/list-test-library.d.ts +0 -44
  156. package/dist/tools/list-test-library.js +0 -83
  157. package/dist/tools/list-test-library.js.map +0 -1
  158. package/dist/tools/list-test-scenarios.d.ts +0 -25
  159. package/dist/tools/list-test-scenarios.js +0 -94
  160. package/dist/tools/list-test-scenarios.js.map +0 -1
  161. package/dist/tools/local-scan.d.ts +0 -40
  162. package/dist/tools/local-scan.js +0 -261
  163. package/dist/tools/local-scan.js.map +0 -1
  164. package/dist/tools/run-test-scenario.d.ts +0 -37
  165. package/dist/tools/run-test-scenario.js +0 -70
  166. package/dist/tools/run-test-scenario.js.map +0 -1
  167. package/dist/tools/scan-pr.d.ts +0 -27
  168. package/dist/tools/scan-pr.js +0 -51
  169. package/dist/tools/scan-pr.js.map +0 -1
  170. package/dist/tools/setup-red-team-target.d.ts +0 -73
  171. package/dist/tools/setup-red-team-target.js +0 -461
  172. package/dist/tools/setup-red-team-target.js.map +0 -1
  173. package/dist/tools/triage-finding.d.ts +0 -41
  174. package/dist/tools/triage-finding.js +0 -125
  175. package/dist/tools/triage-finding.js.map +0 -1
@@ -0,0 +1,240 @@
1
+ # Capsule: Self-consistency without context isolation
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: prompting.self-consistency-no-isolation
7
+ slug: self-consistency-no-isolation
8
+ version: 0.1.0
9
+ category: prompting
10
+ title: Self-Consistency Without Context Isolation
11
+ headline: Vote Without Independence
12
+ description: >
13
+ Detects code that aggregates multiple LLM samples (vote, consensus, ranking)
14
+ while every sample shares the same untrusted context. Majority voting only
15
+ filters random noise — when context is shared, correlated errors override
16
+ correctness and the vote count is mis-read as calibrated confidence.
17
+
18
+ detection_tier: public
19
+ scoring_tier: proprietary
20
+
21
+ applicable_languages:
22
+ - typescript
23
+ - javascript
24
+ - python
25
+
26
+ relevance_filter:
27
+ any_of:
28
+ - dependency: openai
29
+ direct_only: true
30
+ - dependency: "@anthropic-ai/sdk"
31
+ direct_only: true
32
+ - dependency: anthropic
33
+ direct_only: true
34
+ - dependency: "ai"
35
+ direct_only: true
36
+ - dependency: langchain
37
+ direct_only: true
38
+ - dependency: llama-index
39
+ direct_only: true
40
+
41
+ strategies:
42
+ - code: AST
43
+ language: python
44
+ expression: |
45
+ rule:
46
+ kind: for_statement
47
+ has:
48
+ kind: call
49
+ any:
50
+ - pattern: $CLIENT.chat.completions.create($$$)
51
+ - pattern: $CLIENT.messages.create($$$)
52
+ - pattern: openai.ChatCompletion.create($$$)
53
+ evidence_fields: [file_path, line_span, symbol]
54
+ confidence_weight: 0.30
55
+
56
+ - code: AST
57
+ language: typescript
58
+ expression: |
59
+ rule:
60
+ any:
61
+ - pattern: |
62
+ for ($_; $_; $_) {
63
+ $$$
64
+ generateText($$$)
65
+ $$$
66
+ }
67
+ - pattern: |
68
+ [...].map($_ => generateText($$$))
69
+ - pattern: |
70
+ Promise.all([... .map($_ => $CLIENT.chat.completions.create($$$))])
71
+ evidence_fields: [file_path, line_span, symbol]
72
+ confidence_weight: 0.30
73
+
74
+ - code: GRAPH
75
+ expression: |
76
+ same_messages_argument_passed_to_n_completion_calls(n >= 2)
77
+ AND aggregator_observed(any_of: Counter, max(set(.), key=.count), majority_vote, np.argmax, statistics.mode)
78
+ evidence_fields: [graph_path, file_spans, node_ids]
79
+ confidence_weight: 0.30
80
+
81
+ - code: META
82
+ expression: |
83
+ NOT exists_any_of(
84
+ per_sample_retrieval_diversification,
85
+ per_sample_temperature_variation,
86
+ per_sample_seed_variation,
87
+ external_validator_on_facts,
88
+ human_approval_gate
89
+ )
90
+ evidence_fields: [missing_controls]
91
+ confidence_weight: 0.25
92
+
93
+ - code: INFER
94
+ expression: prompt_id:prompting.self-consistency-no-isolation.identify
95
+ evidence_fields: [llm_rationale]
96
+ confidence_weight: 0.15
97
+ trusted: false
98
+
99
+ required_evidence_count: 3
100
+
101
+ control_negations:
102
+ - "presence_of(per_sample_retrieval_diversification)"
103
+ - "presence_of(external_validator_on_facts)"
104
+ - "presence_of(human_approval_gate)"
105
+
106
+ threats:
107
+ - title: Vote count mistaken for calibrated confidence
108
+ stride: [tampering, repudiation]
109
+ description: >
110
+ The application treats agreement across samples as independent confirmation,
111
+ when in fact every sample saw the same poisoned retrieval context or the
112
+ same prompt-injection payload. Downstream actions (auto-approve, send,
113
+ execute) fire under false high-confidence signal.
114
+ remediation: >
115
+ Diversify per-sample retrieval queries, temperatures, or seeds.
116
+ Add an external fact-validator. For high-impact outputs, require a human
117
+ approval gate. Never expose vote count as a confidence number to users
118
+ without disclosing the independence assumption.
119
+ - title: Correlated injection amplification
120
+ stride: [tampering]
121
+ description: >
122
+ A single prompt-injection payload in shared retrieved context biases all N
123
+ samples identically; majority vote then ratifies the attack rather than
124
+ filtering it.
125
+ remediation: >
126
+ Per-sample context isolation. Run independent retrieval (different queries
127
+ or different stores) per sample so an injection only contaminates a subset.
128
+
129
+ fixtures:
130
+ positive:
131
+ - "fixtures/positive/self-consistency-no-isolation/openai_loop_vote_python"
132
+ - "fixtures/positive/self-consistency-no-isolation/anthropic_promise_all_typescript"
133
+ negative:
134
+ - "fixtures/negative/self-consistency-no-isolation/per_sample_diverse_retrieval"
135
+ - "fixtures/negative/self-consistency-no-isolation/single_completion_no_aggregation"
136
+
137
+ lifecycle: draft
138
+ owner: platform-threat-modeling
139
+ tags:
140
+ - prompting
141
+ - self-consistency
142
+ - context-isolation
143
+ - prompt-injection-amplification
144
+
145
+ sensitivity_level: customer_safe
146
+ allowed_execution_modes:
147
+ - local_only
148
+ - local_model
149
+ - hybrid_cloud_eval
150
+
151
+ safe_summary: >
152
+ Multiple LLM completions are aggregated by voting or consensus, but every
153
+ sample sees the same retrieved context or the same user message. Independence
154
+ is assumed and not enforced. A single prompt-injection or a single
155
+ hallucinated retrieval contaminates the vote uniformly; majority count is
156
+ mistaken for calibrated confidence and downstream actions fire under
157
+ false certainty.
158
+
159
+ detect_when: >
160
+ Two or more LLM completions for the same user task are merged by voting,
161
+ consensus, or similarity scoring without independent context isolation —
162
+ no per-sample retrieval diversification, no external validator, no human gate.
163
+
164
+ risk_hints:
165
+ - Shared retrieval/injection in the user message affects every sample the same way
166
+ - Majority vote amplifies systematic bias rather than filtering noise
167
+ - Vote count surfaced as a confidence number is a UX lie when context is shared
168
+ - Async Promise.all with the same messages array is the most common JS shape
169
+
170
+ architectural_signals:
171
+ - Same `messages` argument passed to N completion calls inside a loop or Promise.all
172
+ - majority_vote, Counter, np.argmax, statistics.mode applied to the result array
173
+ - Single retrieval call upstream feeding all samples
174
+
175
+ model_task_prompt_ref: prompts/prompting/self-consistency-no-isolation/identify.md
176
+
177
+ expected_output_schema:
178
+ type: object
179
+ required: [independence_assessment, confidence_claim_risk, evidence_spans]
180
+ properties:
181
+ independence_assessment:
182
+ type: string
183
+ enum: [shared_context, isolated_context, unclear]
184
+ confidence_claim_risk:
185
+ type: string
186
+ enum: [high, medium, low]
187
+ description: How dangerous is the confidence claim users see, given the (lack of) independence
188
+ rationale:
189
+ type: string
190
+ recommended_controls:
191
+ type: array
192
+ items:
193
+ type: string
194
+ enum: [per_sample_retrieval_diversification, external_validator, human_approval, temperature_variation, seed_variation]
195
+ evidence_spans:
196
+ type: array
197
+ items:
198
+ type: object
199
+ required: [file]
200
+ properties:
201
+ file: { type: string }
202
+ start_line: { type: integer }
203
+ end_line: { type: integer }
204
+ note: { type: string }
205
+
206
+ minimum_context_required:
207
+ lines: 80
208
+ symbols:
209
+ - chat.completions.create
210
+ - messages.create
211
+ - generateText
212
+ - Counter
213
+ - majority
214
+ - np.argmax
215
+
216
+ related_patterns:
217
+ - prompting.chain-of-thought-leakage
218
+ - retrieval.shared-context-poisoning
219
+
220
+ repair_contract:
221
+ allowed:
222
+ - Diversify retrieval queries per sample
223
+ - Vary temperature or seed across samples
224
+ - Add an external fact validator on aggregated output
225
+ - Add a human approval gate before high-impact actions
226
+ forbidden:
227
+ - Silently treating vote count as calibrated confidence
228
+ - Removing the aggregation entirely for performance reasons (does not address the architectural issue)
229
+ - Adding more samples without addressing context independence
230
+
231
+ validation_contract:
232
+ requires_tests_pass: false
233
+ requires_static_rules:
234
+ - aggregator_remains_present_after_patch
235
+ - independence_mechanism_introduced
236
+
237
+ unsafe_to_expose_fields:
238
+ - internal_rubric
239
+ - golden_transcripts
240
+ - exploit_templates
@@ -0,0 +1,270 @@
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: |
59
+ const $ROWS = await $QUERY($$$);
60
+ $ROWS.filter($_ => $_.orgId === $REQ.orgId).$$$;
61
+ - pattern: |
62
+ const $ROWS = await $QUERY($$$);
63
+ for (const $R of $ROWS) {
64
+ if ($R.orgId === $REQ.orgId) { $$$ }
65
+ }
66
+ # SSE / stream where filter applied per emit, not at subscription.
67
+ - pattern: |
68
+ $STREAM.on("$_", $EVENT => {
69
+ if ($EVENT.orgId === $REQ.orgId) { $$$ }
70
+ });
71
+ evidence_fields: [file_path, line_span, symbol]
72
+ confidence_weight: 0.35
73
+
74
+ - code: AST
75
+ language: python
76
+ expression: |
77
+ rule:
78
+ any:
79
+ - pattern: |
80
+ rows = $QUERY($$$)
81
+ filtered = [r for r in rows if r.org_id == $REQ.org_id]
82
+ - pattern: |
83
+ for row in $QUERY($$$):
84
+ if row.org_id == request.org_id:
85
+ yield row
86
+ evidence_fields: [file_path, line_span, symbol]
87
+ confidence_weight: 0.35
88
+
89
+ - code: GRAPH
90
+ expression: |
91
+ query_call_returns_rows
92
+ AND filter_predicate_references(req_org_id OR session_org_id)
93
+ AND filter_executes_AFTER(query_call) IN response_handler_or_stream_emit
94
+ AND query_call.where_clause DOES_NOT include org_id
95
+ evidence_fields: [graph_path, file_spans, node_ids]
96
+ confidence_weight: 0.30
97
+
98
+ - code: META
99
+ expression: |
100
+ NOT exists_any_of(
101
+ row_level_security_policy,
102
+ query_helper_with_implicit_org_scope,
103
+ prisma_extension_or_middleware_attaching_org_filter,
104
+ sqlalchemy_loader_option_with_org_scope
105
+ )
106
+ evidence_fields: [missing_controls]
107
+ confidence_weight: 0.20
108
+
109
+ - code: INFER
110
+ expression: prompt_id:security.late-org-filter.identify
111
+ evidence_fields: [llm_rationale]
112
+ confidence_weight: 0.15
113
+ trusted: false
114
+
115
+ required_evidence_count: 3
116
+
117
+ control_negations:
118
+ - "presence_of(row_level_security_policy)"
119
+ - "presence_of(query_helper_with_implicit_org_scope)"
120
+ - "presence_of(prisma_extension_or_middleware_attaching_org_filter)"
121
+
122
+ threats:
123
+ - title: Cross-tenant data leak via SSE / stream pre-filter window
124
+ stride: [information_disclosure, elevation_of_privilege]
125
+ description: >
126
+ In a streaming or async-iterator response, the underlying query returns
127
+ rows from all tenants and the per-emit filter rejects mismatches. A
128
+ brief window where rows are buffered, logged, traced, or partially
129
+ rendered before the filter executes can leak data across tenants. This
130
+ is the SSE / queue/stream variant of the pattern.
131
+ remediation: >
132
+ Push the org/tenant predicate into the data layer — RLS, query helpers,
133
+ ORM middleware. Make every query mandatorily org-scoped at the boundary;
134
+ treat presentation-layer filters as defense in depth, never the primary
135
+ barrier.
136
+ - title: Cross-tenant leak via error path or partial response
137
+ stride: [information_disclosure]
138
+ description: >
139
+ An exception inside the post-query filter loop returns the unfiltered
140
+ buffer or a serialization mid-state. Other tenants' rows reach the
141
+ wire because the only org check sits past the failure point.
142
+ remediation: >
143
+ Same control — RLS or query-time scoping. Plus: serialize the response
144
+ body only after filtering completes; on filter error, return a
145
+ structured error with no payload.
146
+ - title: Logged or traced rows expose other tenants
147
+ stride: [information_disclosure, repudiation]
148
+ description: >
149
+ Observability hooks (request logger, tracer, metrics) often capture the
150
+ raw query result before the presentation-layer filter runs. Other
151
+ tenants' identifiers, names, or PII land in logs the requesting tenant
152
+ should never have seen.
153
+ remediation: >
154
+ Either log only post-filter results, or — better — make the query
155
+ itself org-scoped so the unfiltered result never exists.
156
+
157
+ fixtures:
158
+ positive:
159
+ - "fixtures/positive/late-org-filter/express_sse_post_filter_typescript"
160
+ - "fixtures/positive/late-org-filter/fastapi_iterator_post_filter_python"
161
+ negative:
162
+ - "fixtures/negative/late-org-filter/prisma_middleware_org_scope"
163
+ - "fixtures/negative/late-org-filter/postgres_rls_enabled"
164
+
165
+ lifecycle: draft
166
+ owner: platform-threat-modeling
167
+ tags:
168
+ - multi-tenant
169
+ - cross-tenant-leak
170
+ - data-scoping
171
+ - sse
172
+ - stream
173
+
174
+ sensitivity_level: customer_safe
175
+ allowed_execution_modes:
176
+ - local_only
177
+ - local_model
178
+ - hybrid_cloud_eval
179
+
180
+ safe_summary: >
181
+ Tenant filtering applied after the query — at the response loop, the SSE
182
+ emit, or the stream iterator — instead of inside the query. Any error,
183
+ race, observability hook, or partial response that fires before the filter
184
+ reaches the wire leaks rows across tenants. The fix is to push org/tenant
185
+ scoping down to the data layer (RLS, query helpers, ORM middleware) so the
186
+ unfiltered set never exists in the first place.
187
+
188
+ detect_when: >
189
+ A handler, stream, or async iterator runs a data query, then filters the
190
+ result by `request.orgId` (or a session org) before responding — and the
191
+ query itself doesn't include the org predicate. Multi-tenant routes only.
192
+
193
+ risk_hints:
194
+ - The bug class behind a meaningful share of cross-tenant SaaS incidents
195
+ - SSE / queue / WebSocket variants are the hardest to spot because the filter looks "inside" the loop
196
+ - Logs and traces often capture the unfiltered set even when the response itself is clean
197
+ - Tests often pass because they only run with a single tenant in the test database
198
+
199
+ architectural_signals:
200
+ - Query call followed by an explicit filter referencing a request/session org id
201
+ - SSE or async iterator that yields events conditional on a tenant match
202
+ - No row-level security policy, no implicit-org-scope helper, no ORM middleware
203
+
204
+ model_task_prompt_ref: prompts/security/late-org-filter/identify.md
205
+
206
+ expected_output_schema:
207
+ type: object
208
+ required: [verdict, scope_location, evidence_spans]
209
+ properties:
210
+ verdict:
211
+ type: string
212
+ enum: [late_filter_present, scoped_at_query, partial_scope, unclear]
213
+ scope_location:
214
+ type: string
215
+ enum: [data_layer, query_layer, presentation_layer, multiple, none]
216
+ rationale:
217
+ type: string
218
+ blast_radius:
219
+ type: string
220
+ enum: [single_endpoint, route_family, service_wide, unclear]
221
+ recommended_controls:
222
+ type: array
223
+ items:
224
+ type: string
225
+ enum: [row_level_security, query_helper, orm_middleware, repository_pattern_with_org_scope, none]
226
+ evidence_spans:
227
+ type: array
228
+ items:
229
+ type: object
230
+ required: [file]
231
+ properties:
232
+ file: { type: string }
233
+ start_line: { type: integer }
234
+ end_line: { type: integer }
235
+ note: { type: string }
236
+
237
+ minimum_context_required:
238
+ lines: 100
239
+ symbols:
240
+ - orgId
241
+ - org_id
242
+ - tenant_id
243
+ - filter
244
+ - SSE
245
+ - stream
246
+
247
+ related_patterns:
248
+ - security.idor-via-direct-id
249
+ - security.broken-object-level-authz
250
+
251
+ repair_contract:
252
+ allowed:
253
+ - Push org/tenant scoping into the query (where clause, RLS, ORM middleware)
254
+ - Introduce a repository wrapper that mandates org_id on every method
255
+ - Add a Postgres row-level security policy
256
+ - Keep the presentation-layer filter as defense in depth IN ADDITION TO the data-layer scope
257
+ forbidden:
258
+ - Removing the presentation-layer filter without first introducing a data-layer scope (regresses safety)
259
+ - Treating the patch as complete after only fixing the immediate route — the bug class is structural
260
+
261
+ validation_contract:
262
+ requires_tests_pass: false
263
+ requires_static_rules:
264
+ - data_layer_org_scope_present_after_patch
265
+ - no_unscoped_query_remains_in_route_handler
266
+
267
+ unsafe_to_expose_fields:
268
+ - internal_rubric
269
+ - golden_transcripts
270
+ - exploit_templates
@@ -0,0 +1,68 @@
1
+ {
2
+ "schema_version": "1.0.0",
3
+ "pack_id": "zivis-public",
4
+ "pack_name": "ZIVIS Public Pattern Pack",
5
+ "version": "0.1.0",
6
+ "built_at": "2026-05-06T21:01:49.106Z",
7
+ "tier": "customer_safe",
8
+ "description": "ZIVIS-curated public pattern pack — capsules + inference prompts evaluated locally on the user's machine.",
9
+ "capsules": [
10
+ {
11
+ "id": "agents.privilege-separation",
12
+ "version": "0.1.0",
13
+ "path": "capsules/agents/privilege-separation.yaml",
14
+ "sha256": "31b5984b167ab97ef5c8902327bc80363d1ed3c43d08c82d979b0e34f2b88fde",
15
+ "category": "agents",
16
+ "lifecycle": "draft",
17
+ "applicable_languages": [
18
+ "typescript",
19
+ "javascript",
20
+ "python"
21
+ ]
22
+ },
23
+ {
24
+ "id": "prompting.self-consistency-no-isolation",
25
+ "version": "0.1.0",
26
+ "path": "capsules/prompting/self-consistency-no-isolation.yaml",
27
+ "sha256": "1663fef4b9d544e7ef067501becde5d499eb64e439cf88255b4fae2cdc4d53ea",
28
+ "category": "prompting",
29
+ "lifecycle": "draft",
30
+ "applicable_languages": [
31
+ "typescript",
32
+ "javascript",
33
+ "python"
34
+ ]
35
+ },
36
+ {
37
+ "id": "security.late-org-filter",
38
+ "version": "0.1.0",
39
+ "path": "capsules/security/late-org-filter.yaml",
40
+ "sha256": "34ef82b1da0f690af66579a09355674dd132755fbfc0411ea7c7ef5bbb1b3270",
41
+ "category": "security",
42
+ "lifecycle": "draft",
43
+ "applicable_languages": [
44
+ "typescript",
45
+ "javascript",
46
+ "python",
47
+ "go"
48
+ ]
49
+ }
50
+ ],
51
+ "prompts": [
52
+ {
53
+ "path": "prompts/agents/privilege-separation/identify.md",
54
+ "sha256": "eda7d288f9d1c6f7dfc18d2856300df76e8c4fdb5f18f3490f39ddf7117853e4",
55
+ "capsule_id": "agents.privilege-separation"
56
+ },
57
+ {
58
+ "path": "prompts/prompting/self-consistency-no-isolation/identify.md",
59
+ "sha256": "e05ffb777550a2a79b3c5b8e75d3e3c7fb2da2cd43ab0fcf202a9eda0f29c10f",
60
+ "capsule_id": "prompting.self-consistency-no-isolation"
61
+ },
62
+ {
63
+ "path": "prompts/security/late-org-filter/identify.md",
64
+ "sha256": "8e602179572ace5d457f8582b67e9d6ab29c675e82964481848c95e5ccb83e1e",
65
+ "capsule_id": "security.late-org-filter"
66
+ }
67
+ ]
68
+ }
@@ -0,0 +1,54 @@
1
+ # Inference prompt: agents.privilege-separation — identify
2
+
3
+ You are assisting with secure agentic-AI architecture review. The user is
4
+ working on a codebase that has been flagged by deterministic detectors as
5
+ *possibly* lacking privilege separation between agents. Your job is to
6
+ look at the attached code context and produce a structured verdict.
7
+
8
+ ## Pattern definition
9
+
10
+ **Privilege separation** means each agent in a multi-agent system is bound
11
+ only to the minimum tools required for its role. The anti-pattern is a
12
+ single shared tool registry that every agent inherits.
13
+
14
+ ## What you are evaluating
15
+
16
+ 1. Does the code construct two or more agents (or two or more entry points
17
+ that invoke the same agent factory) with a **shared** tool array?
18
+ 2. Is there a per-agent capability filter, authorization layer, or
19
+ capability-token check between an agent and its tool dispatch? If so,
20
+ the pattern does *not* fire even when tools appear shared.
21
+ 3. If LangGraph is used: are tools bound per node (good), or is one tool
22
+ list passed to a top-level `create_react_agent` covering every node
23
+ (anti-pattern)?
24
+
25
+ ## What does NOT count as privilege separation
26
+
27
+ - Comments mentioning least privilege without code enforcing it.
28
+ - A shared tool list with one agent renamed at runtime.
29
+ - Defensive prompt instructions ("don't use the database tool unless…")
30
+ — prompts are not authorization.
31
+
32
+ ## Output
33
+
34
+ Return JSON only, matching the capsule's `expected_output_schema`:
35
+
36
+ ```json
37
+ {
38
+ "verdict": "absent | present | unclear",
39
+ "confidence": 0.0,
40
+ "rationale": "one paragraph",
41
+ "evidence_spans": [
42
+ { "file": "src/agent.ts", "start_line": 10, "end_line": 40, "note": "..." }
43
+ ]
44
+ }
45
+ ```
46
+
47
+ - `verdict: absent` — the anti-pattern fires (shared registry, no scoping).
48
+ - `verdict: present` — privilege separation is correctly implemented.
49
+ - `verdict: unclear` — the available context is ambiguous; do not guess.
50
+
51
+ Cite line numbers from the snippet only. Do not invent files. Do not
52
+ fabricate evidence. If a concept (e.g. "authorization layer") is mentioned
53
+ but you cannot identify the line that implements it, mark `unclear` and
54
+ explain.
@@ -0,0 +1,60 @@
1
+ # Inference prompt: prompting.self-consistency-no-isolation — identify
2
+
3
+ You are reviewing code that has been flagged as *possibly* aggregating multiple
4
+ LLM samples without context isolation. Your job is to determine whether each
5
+ sample actually sees independent context, or whether they all share the same
6
+ input — making the aggregation a confidence-amplifier rather than a
7
+ confidence-filter.
8
+
9
+ ## What you are evaluating
10
+
11
+ 1. How many LLM completion calls happen for one user request? Identify the
12
+ loop, `Promise.all`, list comprehension, or fan-out construct.
13
+ 2. Does each sample receive the **same** `messages` / prompt argument verbatim,
14
+ or is there per-sample variation (different retrieval query, different
15
+ temperature, different seed, different context window)?
16
+ 3. How is the result aggregated? Voting, ranking, similarity-based merging,
17
+ first-passing-validator, or simple averaging?
18
+ 4. Is there an external check on the aggregated output — e.g. a fact validator,
19
+ tool-output validation, human approval gate?
20
+ 5. Does the user-facing surface advertise the vote count as a "confidence"
21
+ number? That's the strongest tell that independence is being assumed.
22
+
23
+ ## What does NOT count as context isolation
24
+
25
+ - Different agent *names* with the same prompt and same retrieval.
26
+ - Comments saying "ensemble" without per-sample variation in the call.
27
+ - Setting `n=N` on a single OpenAI completion call (the model produces N
28
+ samples but they share the entire prompt and context — same problem).
29
+ - Different temperatures on every sample WITH the same retrieval — partial
30
+ mitigation but not full isolation; mark `unclear` and explain.
31
+
32
+ ## Output
33
+
34
+ Return JSON only, matching the capsule's `expected_output_schema`:
35
+
36
+ ```json
37
+ {
38
+ "independence_assessment": "shared_context | isolated_context | unclear",
39
+ "confidence_claim_risk": "high | medium | low",
40
+ "rationale": "one paragraph",
41
+ "recommended_controls": [
42
+ "per_sample_retrieval_diversification",
43
+ "external_validator",
44
+ "human_approval"
45
+ ],
46
+ "evidence_spans": [
47
+ { "file": "src/agent.ts", "start_line": 10, "end_line": 40, "note": "..." }
48
+ ]
49
+ }
50
+ ```
51
+
52
+ - `shared_context` — every sample sees identical input. The vote is
53
+ amplifying rather than filtering. `confidence_claim_risk` should be `high`
54
+ if any user-facing label calls the vote count a confidence.
55
+ - `isolated_context` — per-sample retrieval, temperature, or seed variation
56
+ IS present. The aggregation is doing real work.
57
+ - `unclear` — context plumbing is too complex to determine from the snippet,
58
+ or the code uses a custom aggregator. Don't guess; ask in the rationale.
59
+
60
+ Cite line numbers from the snippet only. Do not fabricate evidence.