A SQL injection bug in the tool your data engineers use to talk to Snowflake — and worse, the tool your CI runner uses too
CVE-2026-13744 is a SQL injection in the Snowflake CLI (snow) in versions *prior to 3.19*. The CLI fails to properly neutralize attacker-controlled content when constructing SQL — specifically in dollar-quoted YAML spec literals fed to snow spcs service create / execute-job / upgrade, in SHOW ... LIKE patterns under the default STANDARD_ESCAPE_SEQUENCES=FALSE session, and in FQN.sql_identifier paths where single quotes weren't escaped. A crafted YAML spec file or fully-qualified name can break out of the intended literal and append attacker SQL that executes with the CLI user's Snowflake role.
Snowflake's HIGH / 8.3 rating is fair. The AV:N / AC:H / PR:N / UI:R / S:C / C:H/I:H/A:H vector captures it well: no auth on the CLI side (the CLI carries the user's auth), but user interaction is required and complexity is high because the attacker needs to land malicious YAML or identifiers in front of the victim. The Scope:Changed bit matters — when a developer runs snow against a poisoned spec, the SQL executes under that developer's Snowflake role, crossing the CLI/Snowflake trust boundary cleanly.
4 steps from start to impact.
Plant attacker-controlled content
$$-sequence injection to escape dollar-quoted SQL, or crafted single-quote payloads in identifiers. Public Snowflake quickstart repos and shared snowflake.yml templates are realistic injection vectors.- write access to a repo or registry the victim consumes
- victim project uses snow CLI with spec files or programmatic FQNs
- PR review on infrastructure repos
- branch protection in mature CI
Victim invokes vulnerable snow subcommand
snow spcs service create -f spec.yml, snow spcs service execute-job, snow spcs service upgrade, or any subcommand that builds SHOW ... LIKE against attacker-influenced names. The CLI builds SQL by concatenating the attacker's payload into dollar-quoted literals or LIKE patterns.- snow CLI < 3.19 installed
- command run against the poisoned input
- UI:R requirement means a human or pipeline must trigger it
- some shops pin tooling and lag on the vulnerable range
QUERY_HISTORY will record the executed SQL after the fact; no real-time prevention without a fixed CLI.Injected SQL executes under the CLI user's role
USE ROLE whatever the user/runner defaults to. Payload can CREATE a new user, GRANT itself privileges, INSERT INTO exfil tables on an external stage, or DROP regulated tables.- CLI session bound to a usable Snowflake role
- Role separation if the dev/CI runs as a least-privilege role
- network policies restricting Snowflake reachability
ACCESS_HISTORY + LOGIN_HISTORY show the anomalous activity; a tuned SIEM rule on unexpected GRANT ROLE or stage exfil queries catches it.Escalation via elevated CI role
SYSADMIN or ACCOUNTADMIN (very common for IaC-style Snowflake deployments managed via snow or schemachange), the injected SQL inherits that authority. From there: create new privileged users, exfiltrate any warehouse the role can see, or persist via a stored procedure with EXECUTE AS OWNER.- snow CLI used in pipeline with privileged Snowflake role
- Mature deployments use OAuth + short-lived tokens scoped to a least-privilege role
CREATE USER / GRANT OWNERSHIP queries from CI service-account principals — straightforward to alert on.The supporting signals.
| In-the-wild exploitation | None observed as of 2026-06-30. Not on CISA KEV. |
|---|---|
| Public PoC | No public weaponized PoC at disclosure; the Snowflake security advisory describes the $$ dollar-quote breakout and SHOW ... LIKE escaping issue, which is enough to reconstruct. |
| EPSS | Expected low at disclosure (<1st percentile) — typical for client-side CLI bugs requiring UI. |
| KEV status | Not listed. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H → 8.3 HIGH. AC:H and UI:R are the friction points; S:C is what keeps it above 7. |
| Affected versions | Snowflake CLI all versions < 3.19. |
| Fixed version | Snowflake CLI 3.19 and later. No distro backports — snow is shipped via pip/brew/installers by Snowflake directly. |
| Exposure population | Snowflake reports >10K customer accounts; the CLI is the canonical IaC tool for SPCS (Snowpark Container Services) shops. Realistic install base in the low millions across data engineering teams and CI runners. |
| Disclosure | 2026-06-29 via Snowflake Security Bulletins. |
| Reporter | Snowflake internal security / external research credit per vendor bulletin (verify against bulletin page). |
noisgate verdict.
Stays HIGH because the decisive factor is the CI/CD blast radius: snow is canonically deployed inside pipelines running with elevated Snowflake roles, and a poisoned spec turns a PR into arbitrary SQL under those roles. Interactive-developer exploitation is bounded by UI:R and AC:H, but the pipeline-execution role multiplier prevents a downgrade to MEDIUM.
Why this verdict
- Friction is real but not disqualifying:
AC:H+UI:Rmeans an attacker needs to land malicious YAML or identifiers in front of a victim — credible via PR/template poisoning but not drive-by. - Scope:Changed earns the 7+ baseline: the CLI runs under the user's auth context and pushes SQL into the Snowflake control plane — that's a real trust boundary crossing, not just a local crash.
- Role multiplier — CI/CD pipelines:
snowis increasingly used in IaC pipelines bound to SYSADMIN/ACCOUNTADMIN. A poisoned spec in a PR build = warehouse compromise. This is the verdict floor and the reason a friction-only argument can't drag it to MEDIUM. - Role multiplier — interactive devs: typical data engineers run
snowwith scoped roles; blast radius is the schemas they already own. This is the MEDIUM half of the spectrum, but it doesn't set the floor. - No active exploitation, no KEV, no public exploit kit — the only reasons it isn't being pushed to CRITICAL.
Why not higher?
Not CRITICAL because there's no unauthenticated remote path, AC:H and UI:R jointly demand a credible delivery mechanism (poisoned repo, manifest, or social engineering), and there is no observed in-the-wild exploitation. CRITICAL would require evidence of weaponization or a default-deployed high-value target.
Why not lower?
Not MEDIUM because the affected component is a tool widely used in CI/CD with elevated Snowflake credentials — the role-multiplier floor (privileged automation context) holds the verdict at HIGH regardless of how clean your developer workstations are. Downgrading would require evidence that <1% of snow invocations carry SYSADMIN-or-above authority, which is the opposite of typical pipeline usage.
What to do — in priority order.
- Upgrade Snowflake CLI to 3.19 fleet-wide — Replace
snowon every developer workstation, every CI runner, and every container image baked with the CLI. Pin>=3.19inrequirements.txt, brew formulae, and base images. Deploy within 30 days per the noisgate HIGH mitigation SLA; full remediation within 180 days per the remediation SLA, but pipelines should be fixed within days. - Audit CI service-account Snowflake roles — Catalog every pipeline that runs
snowand confirm the bound role is least-privilege. Anything running as SYSADMIN/ACCOUNTADMIN should be downgraded to a project-scoped role with explicit grants. Do this in parallel with the upgrade — vulnerability or not, this is the right posture. - Require PR review for any YAML spec, manifest, or schemachange file — Branch protection + CODEOWNERS on
*.yml,snowflake.yml, and SPCS spec directories. This breaks the poisoned-spec delivery vector regardless of CLI version. - Alert on anomalous Snowflake control-plane SQL from CI principals — Build SIEM rules over
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORYforCREATE USER,GRANT ROLE,ALTER USER ... SET PASSWORD, andCOPY INTO <external_stage>queries originating from service-account users. These are the post-exploitation signals. - Set
STANDARD_ESCAPE_SEQUENCES=TRUEat account level if compatible — Doesn't fix the dollar-quote breakout but closes the backslash-LIKE path. Test in non-prod first; some legacy SQL depends on the default.
- Network ACLs around Snowflake — the attacker SQL runs from your own approved CLI client over your own approved network path. Network controls don't see the injection.
- WAF / SAST on application code — this is a CLI tool bug, not your application's SQL. Your app-tier SQLi defenses don't cover it.
- MFA on the Snowflake user — the CLI session is already authenticated when the injection fires; MFA gated the login, not the per-statement execution.
- Snowflake Native App framework controls — those govern installed apps, not the CLI's outbound SQL.
Crowdsourced verification payload.
Run on any host that has snow installed (developer workstation, build agent, container image). No special privileges needed — invoke as bash check-snow-cli.sh. Returns VULNERABLE for snow --version < 3.19, PATCHED for >= 3.19, UNKNOWN if the CLI isn't found.
#!/usr/bin/env bash
# noisgate verification: CVE-2026-13744 (Snowflake CLI SQL injection)
# Exit 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -u
FIXED_MAJOR=3
FIXED_MINOR=19
if ! command -v snow >/dev/null 2>&1; then
echo "UNKNOWN: snow CLI not found in PATH"
exit 2
fi
RAW="$(snow --version 2>/dev/null || true)"
# Expected format: 'Snowflake CLI version: 3.x.y'
VER="$(echo "$RAW" | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -n1)"
if [ -z "$VER" ]; then
echo "UNKNOWN: could not parse version from: $RAW"
exit 2
fi
MAJ="$(echo "$VER" | cut -d. -f1)"
MIN="$(echo "$VER" | cut -d. -f2)"
if [ "$MAJ" -gt "$FIXED_MAJOR" ]; then
echo "PATCHED: snow $VER"
exit 0
fi
if [ "$MAJ" -eq "$FIXED_MAJOR" ] && [ "$MIN" -ge "$FIXED_MINOR" ]; then
echo "PATCHED: snow $VER"
exit 0
fi
echo "VULNERABLE: snow $VER (< ${FIXED_MAJOR}.${FIXED_MINOR})"
exit 1
If you remember one thing.
snow installed (which snow, container image scans, pip lockfile greps) and pin snowflake-cli-labs>=3.19 in all build manifests. Per the noisgate mitigation SLA for HIGH, complete the CLI upgrade and pipeline role-scoping within 30 days; per the noisgate remediation SLA, drive long-tail workstation upgrades to closure within 180 days. Pair the upgrade with a one-time audit of which Snowflake roles your CI service accounts hold — if any pipeline runs snow as SYSADMIN or ACCOUNTADMIN, that's the real exposure and fixing it pays dividends beyond this CVE. No KEV, no active exploitation — so you do NOT need the hours-window override, but don't let this slip past the 30-day mark either.Sources
- Snowflake CLI release notes 2026
- Snowflake Security Bulletins
- Snowflake CVE considerations (Native Apps)
- SYSTEM$CLIENT_VULNERABILITY_INFO reference
- Related: snowflake-connector-python write_pandas SQLi (GHSA-2vpq-fh52-j3wv)
- Snowflake CVE listing — OpenCVE
- CWE-89: SQL Injection
- CISA KEV catalog (check listing status)
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.