@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.
- package/LICENSE +201 -0
- package/README.md +19 -0
- package/dist/api-client.d.ts +2 -24
- package/dist/api-client.js +32 -52
- package/dist/auth/index.d.ts +1 -22
- package/dist/auth/index.js +17 -38
- package/dist/auth/jwt.d.ts +0 -16
- package/dist/auth/jwt.js +0 -13
- package/dist/auth/keychain.d.ts +6 -32
- package/dist/auth/keychain.js +83 -114
- package/dist/auth/oauth.d.ts +3 -32
- package/dist/auth/oauth.js +67 -61
- package/dist/auth/sessions.d.ts +5 -25
- package/dist/auth/sessions.js +20 -39
- package/dist/auth/token-refresh.d.ts +2 -22
- package/dist/auth/token-refresh.js +33 -36
- package/dist/cli.d.ts +1 -18
- package/dist/cli.js +30 -908
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -7
- package/dist/lib/inspect-cache.d.ts +10 -0
- package/dist/lib/inspect-cache.js +75 -0
- package/dist/lib/next-steps.d.ts +27 -0
- package/dist/lib/next-steps.js +21 -0
- package/dist/matcher/ast-eval.d.ts +8 -0
- package/dist/matcher/ast-eval.js +95 -0
- package/dist/matcher/finding.d.ts +55 -0
- package/dist/matcher/finding.js +1 -0
- package/dist/matcher/index.d.ts +8 -0
- package/dist/matcher/index.js +202 -0
- package/dist/matcher/inference-candidates.d.ts +26 -0
- package/dist/matcher/inference-candidates.js +81 -0
- package/dist/matcher/walker.d.ts +7 -0
- package/dist/matcher/walker.js +71 -0
- package/dist/pattern-pack/index.d.ts +125 -0
- package/dist/pattern-pack/index.js +189 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/agents/privilege-separation.yaml +224 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/prompting/self-consistency-no-isolation.yaml +237 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/retrieval/context-injection-no-validator.yaml +348 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/security/late-org-filter.yaml +266 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/external_validator_on_facts.yaml +37 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/fact_validator_present.yaml +68 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/human_approval_gate.yaml +44 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/langgraph_state_machine_with_per_node_tools.yaml +35 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/per_sample_retrieval_diversification.yaml +38 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/prisma_extension_or_middleware_attaching_org_filter.yaml +31 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/row_level_security_policy.yaml +37 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/source_attribution_present.yaml +58 -0
- package/dist/pattern-packs/zivis-public-0.2.0/manifest.json +167 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/agents/privilege-separation/identify.md +54 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/prompting/self-consistency-no-isolation/identify.md +60 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/retrieval/context-injection-no-validator/identify.md +109 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/security/late-org-filter/identify.md +78 -0
- package/dist/project-binding.d.ts +2 -19
- package/dist/project-binding.js +38 -21
- package/dist/prompts/audit-dependencies.d.ts +2 -0
- package/dist/prompts/audit-dependencies.js +47 -0
- package/dist/prompts/getting-started.d.ts +2 -0
- package/dist/prompts/getting-started.js +37 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +6 -0
- package/dist/resolve-application-id.d.ts +0 -4
- package/dist/resolve-application-id.js +0 -5
- package/dist/sanitize.d.ts +1 -21
- package/dist/sanitize.js +7 -41
- package/dist/server.d.ts +1 -13
- package/dist/server.js +142 -265
- package/dist/tools/artifacts.d.ts +76 -0
- package/dist/tools/artifacts.js +178 -0
- package/dist/tools/check-project.d.ts +5 -18
- package/dist/tools/check-project.js +122 -110
- package/dist/tools/check-repo-trust.d.ts +4 -19
- package/dist/tools/check-repo-trust.js +56 -47
- package/dist/tools/create-diagram.d.ts +0 -5
- package/dist/tools/create-diagram.js +0 -10
- package/dist/tools/create-document.d.ts +0 -5
- package/dist/tools/create-document.js +3 -9
- package/dist/tools/create-finding.d.ts +85 -0
- package/dist/tools/create-finding.js +136 -0
- package/dist/tools/delete-finding.d.ts +19 -0
- package/dist/tools/delete-finding.js +36 -0
- package/dist/tools/devx-run.d.ts +88 -0
- package/dist/tools/devx-run.js +175 -0
- package/dist/tools/discover-local-infra.d.ts +0 -10
- package/dist/tools/discover-local-infra.js +3 -73
- package/dist/tools/enterprise/get-org-zat.d.ts +0 -5
- package/dist/tools/enterprise/get-org-zat.js +0 -6
- package/dist/tools/explain-signal-for-diff.d.ts +34 -0
- package/dist/tools/explain-signal-for-diff.js +75 -0
- package/dist/tools/generate-diagram.d.ts +0 -6
- package/dist/tools/generate-diagram.js +21 -13
- package/dist/tools/get-application-overview.d.ts +0 -5
- package/dist/tools/get-application-overview.js +0 -6
- package/dist/tools/get-application.d.ts +0 -5
- package/dist/tools/get-application.js +0 -6
- package/dist/tools/get-diagram.d.ts +0 -5
- package/dist/tools/get-diagram.js +1 -11
- package/dist/tools/get-document.d.ts +0 -5
- package/dist/tools/get-document.js +0 -6
- package/dist/tools/get-oss-zat.d.ts +0 -5
- package/dist/tools/get-oss-zat.js +0 -7
- package/dist/tools/get-signal.d.ts +24 -0
- package/dist/tools/get-signal.js +75 -0
- package/dist/tools/get-started.d.ts +18 -0
- package/dist/tools/get-started.js +470 -0
- package/dist/tools/get-trust-keys.d.ts +0 -5
- package/dist/tools/get-trust-keys.js +0 -6
- package/dist/tools/import-openapi-endpoints.d.ts +0 -5
- package/dist/tools/import-openapi-endpoints.js +0 -6
- package/dist/tools/inspect-zat.d.ts +0 -5
- package/dist/tools/inspect-zat.js +0 -19
- package/dist/tools/inspect.d.ts +21 -0
- package/dist/tools/inspect.js +222 -0
- package/dist/tools/list-applications.d.ts +1 -6
- package/dist/tools/list-applications.js +0 -6
- package/dist/tools/list-diagrams.d.ts +0 -5
- package/dist/tools/list-diagrams.js +0 -6
- package/dist/tools/list-documents.d.ts +0 -5
- package/dist/tools/list-documents.js +0 -6
- package/dist/tools/list-endpoints.d.ts +1 -6
- package/dist/tools/list-endpoints.js +0 -6
- package/dist/tools/list-signals.d.ts +37 -0
- package/dist/tools/list-signals.js +83 -0
- package/dist/tools/manage-application.d.ts +64 -0
- package/dist/tools/manage-application.js +129 -0
- package/dist/tools/manage-diagram.d.ts +0 -5
- package/dist/tools/manage-diagram.js +0 -16
- package/dist/tools/manage-endpoint-lifecycle.d.ts +80 -0
- package/dist/tools/manage-endpoint-lifecycle.js +180 -0
- package/dist/tools/open-in-ide.d.ts +2 -14
- package/dist/tools/open-in-ide.js +0 -13
- package/dist/tools/review-change.d.ts +34 -0
- package/dist/tools/review-change.js +93 -0
- package/dist/tools/security-memory.d.ts +76 -0
- package/dist/tools/security-memory.js +202 -0
- package/dist/tools/security-review.d.ts +1 -21
- package/dist/tools/security-review.js +8 -108
- package/dist/tools/threat-get-capsule.d.ts +15 -0
- package/dist/tools/threat-get-capsule.js +53 -0
- package/dist/tools/threat-get-inference-prompt.d.ts +15 -0
- package/dist/tools/threat-get-inference-prompt.js +73 -0
- package/dist/tools/threat-list-relevant-capsules.d.ts +17 -0
- package/dist/tools/threat-list-relevant-capsules.js +158 -0
- package/dist/tools/threat-run-matcher.d.ts +17 -0
- package/dist/tools/threat-run-matcher.js +145 -0
- package/dist/tools/update-document.d.ts +0 -5
- package/dist/tools/update-document.js +3 -9
- package/dist/tools/update-endpoint.d.ts +1 -6
- package/dist/tools/update-endpoint.js +0 -7
- package/dist/tools/update-finding.d.ts +61 -0
- package/dist/tools/update-finding.js +80 -0
- package/dist/tools/update-mermaid-source.d.ts +0 -13
- package/dist/tools/update-mermaid-source.js +0 -14
- package/dist/tools/verify-trust-mark.d.ts +0 -5
- package/dist/tools/verify-trust-mark.js +0 -6
- package/dist/types.d.ts +14 -14
- package/dist/types.js +22 -28
- package/package.json +38 -15
- package/dist/api-client.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/jwt.js.map +0 -1
- package/dist/auth/keychain.js.map +0 -1
- package/dist/auth/oauth.js.map +0 -1
- package/dist/auth/sessions.js.map +0 -1
- package/dist/auth/token-refresh.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/project-binding.js.map +0 -1
- package/dist/resolve-application-id.js.map +0 -1
- package/dist/sanitize.js.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/tools/check-project.js.map +0 -1
- package/dist/tools/check-repo-trust.js.map +0 -1
- package/dist/tools/create-diagram.js.map +0 -1
- package/dist/tools/create-document.js.map +0 -1
- package/dist/tools/discover-local-infra.js.map +0 -1
- package/dist/tools/enterprise/capture-evidence.d.ts +0 -54
- package/dist/tools/enterprise/capture-evidence.js +0 -72
- package/dist/tools/enterprise/capture-evidence.js.map +0 -1
- package/dist/tools/enterprise/create-report-ticket.d.ts +0 -34
- package/dist/tools/enterprise/create-report-ticket.js +0 -44
- package/dist/tools/enterprise/create-report-ticket.js.map +0 -1
- package/dist/tools/enterprise/end-pentest-session.d.ts +0 -33
- package/dist/tools/enterprise/end-pentest-session.js +0 -42
- package/dist/tools/enterprise/end-pentest-session.js.map +0 -1
- package/dist/tools/enterprise/generate-report.d.ts +0 -55
- package/dist/tools/enterprise/generate-report.js +0 -111
- package/dist/tools/enterprise/generate-report.js.map +0 -1
- package/dist/tools/enterprise/get-org-zat.js.map +0 -1
- package/dist/tools/enterprise/get-report-status.d.ts +0 -27
- package/dist/tools/enterprise/get-report-status.js +0 -38
- package/dist/tools/enterprise/get-report-status.js.map +0 -1
- package/dist/tools/enterprise/get-threat-model.d.ts +0 -29
- package/dist/tools/enterprise/get-threat-model.js +0 -83
- package/dist/tools/enterprise/get-threat-model.js.map +0 -1
- package/dist/tools/enterprise/list-agents.d.ts +0 -42
- package/dist/tools/enterprise/list-agents.js +0 -95
- package/dist/tools/enterprise/list-agents.js.map +0 -1
- package/dist/tools/enterprise/list-report-issues.d.ts +0 -36
- package/dist/tools/enterprise/list-report-issues.js +0 -50
- package/dist/tools/enterprise/list-report-issues.js.map +0 -1
- package/dist/tools/enterprise/list-threat-models.d.ts +0 -36
- package/dist/tools/enterprise/list-threat-models.js +0 -82
- package/dist/tools/enterprise/list-threat-models.js.map +0 -1
- package/dist/tools/enterprise/manage-actor.d.ts +0 -58
- package/dist/tools/enterprise/manage-actor.js +0 -99
- package/dist/tools/enterprise/manage-actor.js.map +0 -1
- package/dist/tools/enterprise/manage-attack-scenario.d.ts +0 -70
- package/dist/tools/enterprise/manage-attack-scenario.js +0 -89
- package/dist/tools/enterprise/manage-attack-scenario.js.map +0 -1
- package/dist/tools/enterprise/manage-component.d.ts +0 -58
- package/dist/tools/enterprise/manage-component.js +0 -90
- package/dist/tools/enterprise/manage-component.js.map +0 -1
- package/dist/tools/enterprise/manage-data-asset.d.ts +0 -53
- package/dist/tools/enterprise/manage-data-asset.js +0 -90
- package/dist/tools/enterprise/manage-data-asset.js.map +0 -1
- package/dist/tools/enterprise/manage-data-flow.d.ts +0 -57
- package/dist/tools/enterprise/manage-data-flow.js +0 -98
- package/dist/tools/enterprise/manage-data-flow.js.map +0 -1
- package/dist/tools/enterprise/manage-finding.d.ts +0 -69
- package/dist/tools/enterprise/manage-finding.js +0 -106
- package/dist/tools/enterprise/manage-finding.js.map +0 -1
- package/dist/tools/enterprise/manage-security-control.d.ts +0 -59
- package/dist/tools/enterprise/manage-security-control.js +0 -96
- package/dist/tools/enterprise/manage-security-control.js.map +0 -1
- package/dist/tools/enterprise/manage-test-case.d.ts +0 -88
- package/dist/tools/enterprise/manage-test-case.js +0 -119
- package/dist/tools/enterprise/manage-test-case.js.map +0 -1
- package/dist/tools/enterprise/promote-finding-to-issue.d.ts +0 -36
- package/dist/tools/enterprise/promote-finding-to-issue.js +0 -65
- package/dist/tools/enterprise/promote-finding-to-issue.js.map +0 -1
- package/dist/tools/enterprise/publish-report-version.d.ts +0 -34
- package/dist/tools/enterprise/publish-report-version.js +0 -75
- package/dist/tools/enterprise/publish-report-version.js.map +0 -1
- package/dist/tools/enterprise/publish-test-to-library.d.ts +0 -31
- package/dist/tools/enterprise/publish-test-to-library.js +0 -40
- package/dist/tools/enterprise/publish-test-to-library.js.map +0 -1
- package/dist/tools/enterprise/record-test-result.d.ts +0 -67
- package/dist/tools/enterprise/record-test-result.js +0 -75
- package/dist/tools/enterprise/record-test-result.js.map +0 -1
- package/dist/tools/enterprise/start-pentest-session.d.ts +0 -35
- package/dist/tools/enterprise/start-pentest-session.js +0 -50
- package/dist/tools/enterprise/start-pentest-session.js.map +0 -1
- package/dist/tools/enterprise/sync-report-section.d.ts +0 -41
- package/dist/tools/enterprise/sync-report-section.js +0 -79
- package/dist/tools/enterprise/sync-report-section.js.map +0 -1
- package/dist/tools/enterprise/update-report-issue.d.ts +0 -55
- package/dist/tools/enterprise/update-report-issue.js +0 -69
- package/dist/tools/enterprise/update-report-issue.js.map +0 -1
- package/dist/tools/generate-diagram.js.map +0 -1
- package/dist/tools/get-agent-test-results.d.ts +0 -41
- package/dist/tools/get-agent-test-results.js +0 -86
- package/dist/tools/get-agent-test-results.js.map +0 -1
- package/dist/tools/get-application-overview.js.map +0 -1
- package/dist/tools/get-application.js.map +0 -1
- package/dist/tools/get-artifact-content.d.ts +0 -29
- package/dist/tools/get-artifact-content.js +0 -86
- package/dist/tools/get-artifact-content.js.map +0 -1
- package/dist/tools/get-diagram.js.map +0 -1
- package/dist/tools/get-document.js.map +0 -1
- package/dist/tools/get-finding-details.d.ts +0 -28
- package/dist/tools/get-finding-details.js +0 -43
- package/dist/tools/get-finding-details.js.map +0 -1
- package/dist/tools/get-findings.d.ts +0 -57
- package/dist/tools/get-findings.js +0 -103
- package/dist/tools/get-findings.js.map +0 -1
- package/dist/tools/get-oss-zat.js.map +0 -1
- package/dist/tools/get-recon-scan.d.ts +0 -27
- package/dist/tools/get-recon-scan.js +0 -46
- package/dist/tools/get-recon-scan.js.map +0 -1
- package/dist/tools/get-scan-output.d.ts +0 -27
- package/dist/tools/get-scan-output.js +0 -64
- package/dist/tools/get-scan-output.js.map +0 -1
- package/dist/tools/get-scenario-details.d.ts +0 -27
- package/dist/tools/get-scenario-details.js +0 -46
- package/dist/tools/get-scenario-details.js.map +0 -1
- package/dist/tools/get-test-case-results.d.ts +0 -37
- package/dist/tools/get-test-case-results.js +0 -66
- package/dist/tools/get-test-case-results.js.map +0 -1
- package/dist/tools/get-test-details.d.ts +0 -29
- package/dist/tools/get-test-details.js +0 -49
- package/dist/tools/get-test-details.js.map +0 -1
- package/dist/tools/get-trust-keys.js.map +0 -1
- package/dist/tools/import-openapi-endpoints.js.map +0 -1
- package/dist/tools/inspect-zat.js.map +0 -1
- package/dist/tools/list-agent-test-cases.d.ts +0 -41
- package/dist/tools/list-agent-test-cases.js +0 -73
- package/dist/tools/list-agent-test-cases.js.map +0 -1
- package/dist/tools/list-applications.js.map +0 -1
- package/dist/tools/list-diagrams.js.map +0 -1
- package/dist/tools/list-documents.js.map +0 -1
- package/dist/tools/list-endpoints.js.map +0 -1
- package/dist/tools/list-recon-scans.d.ts +0 -36
- package/dist/tools/list-recon-scans.js +0 -74
- package/dist/tools/list-recon-scans.js.map +0 -1
- package/dist/tools/list-scan-artifacts.d.ts +0 -41
- package/dist/tools/list-scan-artifacts.js +0 -63
- package/dist/tools/list-scan-artifacts.js.map +0 -1
- package/dist/tools/list-scans.d.ts +0 -44
- package/dist/tools/list-scans.js +0 -91
- package/dist/tools/list-scans.js.map +0 -1
- package/dist/tools/list-test-library.d.ts +0 -44
- package/dist/tools/list-test-library.js +0 -83
- package/dist/tools/list-test-library.js.map +0 -1
- package/dist/tools/list-test-scenarios.d.ts +0 -31
- package/dist/tools/list-test-scenarios.js +0 -66
- package/dist/tools/list-test-scenarios.js.map +0 -1
- package/dist/tools/local-scan.d.ts +0 -40
- package/dist/tools/local-scan.js +0 -261
- package/dist/tools/local-scan.js.map +0 -1
- package/dist/tools/manage-diagram.js.map +0 -1
- package/dist/tools/open-in-ide.js.map +0 -1
- package/dist/tools/run-test-scenario.d.ts +0 -37
- package/dist/tools/run-test-scenario.js +0 -70
- package/dist/tools/run-test-scenario.js.map +0 -1
- package/dist/tools/scan-pr.d.ts +0 -27
- package/dist/tools/scan-pr.js +0 -51
- package/dist/tools/scan-pr.js.map +0 -1
- package/dist/tools/security-review.js.map +0 -1
- package/dist/tools/setup-red-team-target.d.ts +0 -79
- package/dist/tools/setup-red-team-target.js +0 -430
- package/dist/tools/setup-red-team-target.js.map +0 -1
- package/dist/tools/triage-finding.d.ts +0 -47
- package/dist/tools/triage-finding.js +0 -116
- package/dist/tools/triage-finding.js.map +0 -1
- package/dist/tools/update-document.js.map +0 -1
- package/dist/tools/update-endpoint.js.map +0 -1
- package/dist/tools/update-mermaid-source.js.map +0 -1
- package/dist/tools/verify-trust-mark.js.map +0 -1
- 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
|
package/dist/pattern-packs/zivis-public-0.2.0/controls/per_sample_retrieval_diversification.yaml
ADDED
|
@@ -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
|