Skip to content

Snowflake red-team iter-4 — Chain J, detection pairs, SPCS matrix, Native App empirical, Guardrails tier-2#47

Merged
AndrewAltimit merged 8 commits into
mainfrom
snowflake-rt-iter-4
May 15, 2026
Merged

Snowflake red-team iter-4 — Chain J, detection pairs, SPCS matrix, Native App empirical, Guardrails tier-2#47
AndrewAltimit merged 8 commits into
mainfrom
snowflake-rt-iter-4

Conversation

@AndrewAltimit
Copy link
Copy Markdown
Owner

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:

  • Chain J — third-party-SaaS credential replay. The 2026 analytics-SaaS-token incident is now a full chain with end-to-end PoC, not a paragraph in the ecosystem-context section. Post-MFA generalization of Chain A: credential held by a partner SaaS, replayed from attacker infrastructure after the partner is compromised. partner_integration_audit.py flags partner-integration users with no network policy or with policy CIDRs that don't cover the documented partner egress.
  • Detection pairs. Every chain now has both an ACCOUNT_USAGE-shaped Sigma and a Snowflake-Trail-shaped Sigma. Chain H gets a dedicated rule (previously piggy-backed on storage-integration-misuse). Cortex Code gets a behavioral pair that does not decay with the version string.
  • PAT discovery. Endpoint-side filesystem walker — SnowSQL config, SnowCLI TOML, dbt profiles, Airflow conn, GHA workflow secret refs, macOS keychain refs, plain key files, and connector debug-log master-key leaks. Filesystem-only; fixture-scoped via assert_under_fixture_root.
  • Native App supply-chain empirical PoC. New module under 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 empirical matrix. Chain H's "open empirical question" framing replaced with a modeled inspection-depth x EAI-rule-shape x destination matrix. spcs_egress_probe.py walks the grid; lab-validation SQL captures the ACCOUNT_USAGE.INTEGRATIONS + NETWORK_RULES + SERVICES projection for tenant confirmation.
  • Guardrails harness reframe. The "regex catches ~half" framing is gone. Two baseline tiers — regex (tier-1) and semantic-shape (tier-2) — and the harness reports the delta. Single-percentage framing replaced with per-class comparison.

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>/egress with configurable inspection depth (Chain H matrix)

Commit map

Commit Subject
56eeb2b mock: chain-J / chain-C / chain-H endpoint extensions
3712d46 Chain J — third-party-SaaS credential replay
88fcf98 detection — Trail-event pairs + Chain H + behavioral Cortex Code
3699899 PAT discovery — endpoint-side credential walker
4dd5bf6 Chain C — Native App supply-chain empirical PoC
544c2dc Chain H — SPCS empirical egress matrix
badf9eb Guardrails harness — tier-1 / tier-2 reframe
5059207 final — HTML report, screenshot baselines, indexes, READMEs

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 clean
  • python3 ci/check_mock_services_loopback.py — 8 mock services, all loopback-bound
  • All other CI checks green (AiTM, kernel-lpe, LOLDrivers, no real tenants, no real RMM, no suspicious .pth, no committed drivers)
  • pytest reports/snowflake-platform-assessment/tests/ — visual-regression suite passes against refreshed baselines for the three modified pages (index, attack_chains, detection)
  • Smoke-tested tier-2 guardrail on a paraphrased payload — tier-1 misses, tier-2 catches via directive_shape + url_near_credential; benign payload passes both tiers clean
  • Mock-snowflake imports cleanly with new state, 30 routes registered; new endpoints respond
  • End-to-end run of version_bump_sim.py against a freshly-launched mock to confirm the audit-row schema matches what native_app_unexpected_version_bump.yml and native_app_privilege_bump.yml consume (requires a running mock-snowflake — local smoke before merge)
  • End-to-end run of spcs_egress_probe.py to confirm the printed matrix matches the analytical-doc table (likewise local smoke before merge)
  • End-to-end run of the guardrails harness to capture a tier1-vs-tier2 JSON report for the assessment appendix

Notes for review

  • All eight chain headings A-J now have both Sigma + Trail coverage (with one exception by design: Chain C does not have a separate Trail event because Native App lifecycle still surfaces through ACCOUNT_USAGE.APPLICATIONS).
  • The SPCS matrix is modeled, not tenant-confirmed. The analytical doc Out-of-Scope section says so explicitly and the chain doc carries the same caveat.
  • The Guardrails tier-2 is a pattern-only approximation. It does not invoke a language model and cannot reason about intent — the harness README is explicit that the result is a comparison shape, not a vendor benchmark.

Generated with Claude Code

AI Agent Bot and others added 8 commits May 15, 2026 10:15
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>
@AndrewAltimit AndrewAltimit merged commit e827f3a into main May 15, 2026
2 checks passed
@AndrewAltimit AndrewAltimit deleted the snowflake-rt-iter-4 branch May 15, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant