Snowflake red-team iter-4 — Chain J, detection pairs, SPCS matrix, Native App empirical, Guardrails tier-2#47
Merged
Merged
Conversation
Extends the lab mock-snowflake with the endpoints the iter-4 PoCs
need, keeping all mock plumbing in one place so the per-item commits
that follow don't have to touch infra.
Chain J (partner-integration credential replay):
- `_network_policies` registry with `CORP_VPN_ONLY` and a documented
partner-egress policy `PARTNER_ANALYTICS_VENDOR_EGRESS`
- Two seeded partner-integration users: `partner_acme_analytics`
(good config — policy bound) and `partner_bi_vendor` (the Chain J
victim shape — no policy bound). Both tagged with `partner_id`.
- `GET /api/v2/users` and `GET /api/v2/network-policies` so the
audit tool can read the inventory + policy graph in one shot.
Chain C (Native App Marketplace supply-chain):
- `_app_listings`, `_app_installations`, `_app_history` state
- `POST /api/v2/native-apps/publish` (provider version-bump)
- `POST /api/v2/native-apps/install` (consumer install or auto-upgrade
emitting an APPLICATION_HISTORY record with the schema the existing
`native_app_unexpected_version_bump.yml` rule consumes)
- `GET /api/v2/native-apps/applications` and `/history`
Chain H (SPCS over-broad EAI egress):
- `_spcs_services`, `_spcs_egress_log`
- `POST /api/v2/spcs/services` accepting `inspection_depth` and
`eai_rule_shape` knobs
- `POST /api/v2/spcs/services/<name>/egress` returning ALLOW/DENY
under a documented decision function (DNS_ONLY / SNI / L7 × WILDCARD
/ SCOPED / DENY_BY_DEFAULT)
- `GET /api/v2/spcs/services` and `/api/v2/spcs/egress-log`
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promotes the 2026 analytics-SaaS-token incident from a paragraph in
the ecosystem-context section to a full Chain J with end-to-end PoC,
lab-validation SQL, and detection rule pairs. Chain J is the
post-MFA generalization of Chain A: where the 2024 UNC5537 campaign
exploited developer-endpoint credentials, the 2026 SaaS-vendor
incident exploited the same primitive with the credential held by a
partner SaaS — outside the customer's perimeter, network policy, and
MFA controls. The mitigation is identical in shape: a network policy
bound to every partner-integration user with `allowed_ip_list`
matching the partner's documented egress range.
This commit also folds in the analytical-doc updates for Chain H
(SPCS matrix replaces "open empirical question") and Chain I
(Guardrails harness reframe — comparison instead of single
pass-through number). Those updates are co-located here because they
share the analytical-doc file; the code that backs them ships in the
SPCS-empirical and guardrails-harness commits below.
Tooling:
- `tools/cloud-identity/snowflake/partner_integration_audit.py`
reads the user inventory + partner registry, flags partner users
with no policy bound or with `allowed_ip_list` not covering the
documented partner egress CIDRs
- `lab-validation/partner_integration_baseline.sql` for tenant
validation
- Sigma + Trail-event pair for Chain J detection
Comparison doc adds the Chain J row (Snowflake → Databricks
analogue) and an updated Chain H row referencing the new matrix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… Cortex Code
Closes the iter-3 detection gaps:
- Chain H dedicated Sigma — previously the chain piggy-backed on
`snowflake_storage_integration_misuse.yml`. New rule fires
specifically on `EXTERNAL ACCESS INTEGRATION` create/alter with
wildcard or `OPEN_ANY` rules.
- Behavioral Cortex Code Sigma — pairs with the existing version-
string-only `cortex_code_pre_1_0_25.yml`. Fires when a Cortex Code
session is followed within a correlation window by a Snowflake
login from an IP outside the developer host's known egress range.
Does not decay with the version string.
- Trail-event-shaped Sigma pairs for chains E (storage integration),
F (key-pair JWT), G (share + replication, two rules), H (SPCS EAI),
and I (Cortex Agent directive follow-up). Every chain now has both
an ACCOUNT_USAGE-shaped rule and a Trail-event-shaped rule; the
SOC picks whichever matches the customer's audit-ingestion surface.
Updated `detection/snowflake/README.md` to a two-column table
(ACCOUNT_USAGE Sigma vs. Trail Sigma) so the dual coverage is the
primary view.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the iter-3 gap "PAT scope enum exists; discovery doesn't."
`pat_scope_enum.py` assumes a token is already in hand;
`pat_discovery.py` is the prior step — walking a compromised
endpoint (developer workstation, CI runner, airflow container) to
find where Snowflake credentials actually live.
Storage classes recognised:
- SnowSQL legacy config (`~/.snowsql/config`)
- SnowCLI TOML (`~/.snowflake/config.toml`,
`~/.snowflake/connections.toml`)
- dbt profiles (`~/.dbt/profiles.yml`)
- Airflow connection extras + AIRFLOW_CONN_* env vars
- Generic env: SNOWFLAKE_PAT / SNOWFLAKE_PASSWORD /
SNOWFLAKE_PRIVATE_KEY*, SNOWSQL_PWD
- GitHub Actions workflows referencing snowflake secrets
- macOS keychain reference scripts
- Plain `.pem` / `.p8` / `snowflake*.key` files
- Connector debug-log master-key leaks
(CVE-2025-27496 / CVE-2025-46329 class)
Containment: filesystem-only, no network. Every file op runs through
`assert_under_fixture_root` against `EXPLOIT_FIXTURE_ROOT`; the tool
will refuse to scan an unscoped home directory.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the iter-3 gap "Chain C is the highest-impact chain and the
least empirically grounded." Mirrors the marketplace-side counterpart
of `shai-hulud-class` for npm: a compromised provider account
version-bumps an installed Native App with an added consumer-side
privilege grant; consumers with auto-update enabled receive it
without re-consent.
- `manifest_builder.py` builds v1 / v2 manifests as dataclasses; v2
variants include a `v2-priv` (adds `READ ON SCHEMA <CONSUMER>.HR_PII`)
and a `v2-eai` (adds an EXTERNAL ACCESS INTEGRATION).
- `version_bump_sim.py` drives the full publish → install → bump →
auto-upgrade flow against the lab mock; surfaces the
`manifest_diff_added` field carrying `PRIVILEGE:` / `EXTERNAL
ACCESS INTEGRATION:` tokens.
- `detection/sigma/native_app_privilege_bump.yml` + Trail-event
pair — fires specifically on `PRIVILEGE:` additions, severity
`critical` (read-privilege variant is hard to recover from once
the read has run).
- `lab-validation/observe_application_history.sql` for tenant-side
confirmation against `ACCOUNT_USAGE.APPLICATION_INSTALLATION_HISTORY`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the iter-3 "open empirical question" framing on Chain H by
shipping a structural matrix the analytical doc now embeds. The mock
extensions (sibling commit) accept `inspection_depth` and
`eai_rule_shape` knobs; this PoC walks the full
DNS-only / SNI / L7 × WILDCARD / SCOPED / DENY_BY_DEFAULT × loopback /
approved-vendor / attacker-domain grid.
Findings (modeled, not tenant-confirmed):
- WILDCARD / OPEN_ANY EAI rule is a sanctioned exfil channel at
every inspection depth.
- SCOPED rule is structurally permissive at DNS-only inspection —
hosts behind a shared A record bypass the gate.
- SCOPED rule enforces at SNI and L7.
- DENY_BY_DEFAULT denies at every depth.
The matrix reads vendor docs structurally; tenant validation
remains a follow-on for organizations with an SPCS deployment.
`lab-validation/spcs_egress_observe.sql` captures the
ACCOUNT_USAGE projection that pairs with the probe — INTEGRATIONS +
NETWORK_RULES + SERVICES, plus a pointer to the cloud-provider audit
where Snowflake itself doesn't surface SPCS egress flows.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the iter-3 critique that the harness measures against a
"deliberately weak first-gen regex" and reports "regex catches
~half." A strawman knockdown is not a defensible empirical claim.
Reframe: the harness now ships two baseline tiers, runs the same
corpus through both, and reports the **delta** — which payload
classes tier-2 recovers that tier-1 misses, and which classes either
tier still leaves uncovered. The single-percentage framing is gone
from the headline output.
- Tier 1 — first-gen regex baseline (literal pattern match).
- Tier 2 — semantic-shape baseline: imperative-mood directives
pointed at the AI, role-assertion markers (`System:` /
`ASSISTANT:`), fenceless sensitive SQL (`CREATE SHARE`,
`ALTER SHARE ADD ACCOUNTS`, `COPY INTO @<stage>`,
`ALTER NETWORK POLICY`), URL-near-credential shapes,
long-base64 / zero-width / confusable-script smells, and
markdown-template render shapes. Best-effort approximation of a
semantic-aware vendor product; not Snowflake's actual rule set.
The harness gains a `--tier` flag (`1`, `2`, or `both`) and the
mock's request body accepts a `tier` selector. `run_harness.py`
prints per-tier TP/FN/TN/FP plus the recovered / lost diff against
the same corpus.
README rewritten to drop pass-through-rate framing entirely and lead
with the comparison shape. The corresponding analytical-doc
reframe (Chain I + Out-of-Scope section) ships in the Chain J commit
since it shares the analytical doc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…READMEs
Surfaces all iter-4 work in the audience-facing report and the
navigational indexes.
HTML report:
- index.html — Chain J added to the key-findings table.
- attack-chains.html — Chain J narrative added; Chain H expanded
with the inspection-depth × EAI-rule-shape matrix callout.
- detection.html — Chain J detection query
(partner-integration users with no network policy bound).
- Three screenshot baselines refreshed (`index`, `attack_chains`,
`detection`) for the visual-regression test suite. Other four
pages unchanged.
Indexes / READMEs:
- CLAUDE.md — module-index entries updated for the new tooling
(partner-integration audit, PAT discovery, SPCS matrix probe,
Native App version-bump).
- tools/cloud-identity/snowflake/README.md — title + new sections
for pat_discovery.py and partner_integration_audit.py.
- tools/lateral-movement/snowflake-pivot/README.md — title updated
to include Chain H; new section for spcs_egress_probe.py.
CI green across all 11 checks (snowflake-tools syntax, detection
pairing across 40 module trees, report nav-parity + internal-link
integrity, mock-services loopback, AiTM, kernel-lpe, LOLDrivers,
no real tenants, no real RMM, no suspicious .pth, no committed
drivers). Visual-regression tests pass against refreshed baselines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves the seven follow-on items from the iter-3 deep-dive review. Eight grouped commits — one for the mock infrastructure changes plus one per item.
New work:
partner_integration_audit.pyflags partner-integration users with no network policy or with policy CIDRs that don't cover the documented partner egress.assert_under_fixture_root.tools/supply-chain/snowflake-native-app/with manifest builder, version-bump simulator, two paired Sigma rules (privilege bump -> critical severity), and lab-validation SQL. Closes the iter-3 gap that the highest-impact chain (Chain C) had no end-to-end PoC.spcs_egress_probe.pywalks the grid; lab-validation SQL captures theACCOUNT_USAGE.INTEGRATIONS + NETWORK_RULES + SERVICESprojection for tenant confirmation.Mock-snowflake extensions:
GET /api/v2/users+/api/v2/network-policies(Chain J inventory)POST /api/v2/native-apps/{publish,install}+GET history,applications(Chain C audit)POST /api/v2/spcs/services/<name>/egresswith configurable inspection depth (Chain H matrix)Commit map
Test plan
python3 ci/check_snowflake_tools_syntax.py— passes (17 modules)python3 tools/ci/check_detection_pairing.py— passes (40 module trees)python3 ci/check_snowflake_report_integrity.py— nav parity + internal links cleanpython3 ci/check_mock_services_loopback.py— 8 mock services, all loopback-boundpytest reports/snowflake-platform-assessment/tests/— visual-regression suite passes against refreshed baselines for the three modified pages (index,attack_chains,detection)directive_shape+url_near_credential; benign payload passes both tiers cleanversion_bump_sim.pyagainst a freshly-launched mock to confirm the audit-row schema matches whatnative_app_unexpected_version_bump.ymlandnative_app_privilege_bump.ymlconsume (requires a running mock-snowflake — local smoke before merge)spcs_egress_probe.pyto confirm the printed matrix matches the analytical-doc table (likewise local smoke before merge)Notes for review
ACCOUNT_USAGE.APPLICATIONS).Generated with Claude Code