← Back to Feed CACHED · 2026-06-30 01:52:25 · CACHE_KEY CVE-2026-13752
CVE-2026-13752 · CWE-89 · Disclosed 2026-06-29

Improper neutralization of parameters in Snowflake CLI versions prior to 3

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

A developer-tool parameter parser that trusts the dev a little too much

CVE-2026-13752 is an *improper input neutralization* (CWE-89) flaw in the Snowflake CLI (snow) prior to 3.19. When the CLI processes certain user-supplied parameters — likely in YAML spec files, --variable substitutions, or identifier handling consistent with other 2026 Snowflake CLI fixes — the values are interpolated into the SQL sent to Snowflake without proper escaping. A crafted parameter value (e.g. embedding $$, single quotes, or identifier separators) can break out of the intended literal/identifier context and append attacker-chosen SQL that executes under the invoking user's Snowflake role.

Vendor scored this MEDIUM (6.0) with vector AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:N. That vector is honest: local attack, high complexity, requires the victim to run the CLI on attacker-influenced input. In practice this is a *trojaned project file* or *malicious teammate* threat model, not a remote pwn. For a defender managing 10,000 hosts, this is a developer-laptop / CI-runner concern with a narrow blast radius — Snowflake's MEDIUM is slightly hot for the typical deployment, hence the downgrade to LOW.

"Local-only SQL injection in a developer CLI tool. Vendor's MEDIUM is generous — this is a workstation-bound bug, not a fleet event."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Attacker stages a malicious project artifact

The attacker plants a crafted snowflake.yml, deployment manifest, or parameter value (e.g., in a PR, a shared repo, a Slack snippet, or a downloaded sample app). The payload embeds SQL-breaking sequences inside a field the CLI will later interpolate into a query. No tooling required beyond a text editor.
Conditions required:
  • Write access to a file/PR/artifact the victim will consume
  • Knowledge of which CLI parameter is unsafely interpolated
Where this breaks in practice:
  • Code review on the PR catches odd $$ or quote sequences
  • Repo CODEOWNERS / branch protection blocks untrusted contributors
Detection/coverage: Pre-commit secret/SQL-pattern scanners (e.g., semgrep rules on snowflake.yml)
STEP 02

Developer runs snow against the poisoned input

The victim invokes a command such as snow sql -f ..., snow spcs service create, snow app deploy, or similar against the trojaned manifest. The CLI builds the SQL string client-side and sends it to Snowflake over an authenticated session.
Conditions required:
  • Victim has a valid Snowflake session / configured connection
  • Victim executes the CLI with the attacker's input as an argument or file
Where this breaks in practice:
  • UI:R requirement — needs a human to run the command
  • Many shops gate Snowflake credentials behind SSO + short-lived tokens
Detection/coverage: Snowflake QUERY_HISTORY shows the malformed/extra statements
STEP 03

Injected SQL executes under the victim's Snowflake role

The escaped payload runs as additional statements in the same session — GRANT, CREATE USER, COPY INTO @stage for exfil, or DROP for destruction. Scope is bounded by the role's privileges; a SYSADMIN/ACCOUNTADMIN victim is catastrophic, an ANALYST victim is contained.
Conditions required:
  • Victim's role has the privileges the payload needs
  • No row/object-level masking blocking the target data
Where this breaks in practice:
  • Least-privilege role design limits blast radius
  • Network policies / IP allowlists do not help here — traffic is from the legit user
Detection/coverage: Snowflake Trust Center / ACCESS_HISTORY and QUERY_HISTORY anomaly rules; Datadog/Panther Snowflake monitors
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. No public reports, no incident disclosures as of 2026-06-30.
Public PoCNo public PoC repo identified. Pattern is consistent with prior Snowflake CLI 2026 fixes (YAML $$ break-out, SHOW … LIKE literal handling, FQN.sql_identifier escaping).
EPSSNot yet scored at disclosure (typical for sub-week-old developer-tool CVEs); expect <1st percentile.
KEVNot listed. Unlikely to qualify — no remote vector.
CVSS vectorAV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:N — local, high complexity, low priv, user interaction; high C/I, no A impact.
Affected versionsSnowflake CLI (snowflake-cli) < 3.19
Fixed version3.19.0 (PyPI: snowflake-cli==3.19.0)
Exposure populationPer PyPI download stats Snowflake CLI sees ~hundreds of thousands of monthly installs — but the attack surface is *developer endpoints and CI runners*, not internet-facing infra. Shodan/Censys: not applicable (no listener).
Disclosed2026-06-29
ReporterSnowflake PSIRT (researcher attribution not yet published)
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to LOW (3.8/10)

The single most decisive factor is the local attack vector combined with required user interaction on attacker-supplied input — this is a trojaned-project-file threat model, not a remote exploit. Blast radius is further bounded by the invoking user's Snowflake role, which in a least-privilege account is narrow.

HIGH vendor severity is overstated for typical deployments
MEDIUM exact injection sink (YAML field vs. identifier vs. variable) pending PSIRT detail
HIGH no in-the-wild exploitation

Why this verdict

  • Local + UI:R + AC:H — three friction multipliers stacked. Attacker must place a file, get the victim to run a specific CLI command against it, and have the payload survive any review.
  • Blast radius is role-scoped. Damage equals what the victim's Snowflake role can already do. Shops following Snowflake's documented least-privilege model (functional roles, no default ACCOUNTADMIN) contain this to a single dataset.
  • Role multiplier: if a CI/CD service account running snow holds ACCOUNTADMIN or SECURITYADMIN, the chain ends in tenant-wide takeover of the Snowflake account. However, the affected component (CLI binary) is *not canonically* a high-value-role component the way a hypervisor or DC is — the high-value role share is well under 10% of installs (most snow invocations are interactive developer sessions with scoped roles), so the CRITICAL floor does not trip. HIGH floor also does not trip because the high-privilege-CI-account population is itself a minority of installs AND requires the trojaned-input prerequisite.
  • No remote vector, no KEV, no PoC, no listener for scanners to find. EPSS will sit near zero.

Why not higher?

MEDIUM would be defensible if the CLI were commonly run by ACCOUNTADMIN-class automation against untrusted inputs — but the documented and best-practice pattern is scoped functional roles. HIGH is off the table because there is no remote vector, no unauthenticated path, and no service-listener exposure.

05 · Compensating Control

What to do — in priority order.

  1. Upgrade snowflake-cli to 3.19.0+ on developer laptops and CI runners — This is a code-fix bug; the real remediation is the package bump. Pin in requirements.txt/pyproject.toml, rebuild base CI images. Per noisgate remediation SLA for LOW: backlog hygiene — fold into the normal dependency-refresh cycle, target within ~365 days but ideally next CI image rebuild.
  2. Audit Snowflake roles used by CI service accounts and developer SSO — Confirm no automation runs snow under ACCOUNTADMIN/SECURITYADMIN. Move to functional roles (APP_DEPLOYER, SCHEMA_OWNER) with explicit grants. This is the single biggest blast-radius reducer for this CVE and the next one.
  3. Enable Snowflake ACCESS_HISTORY + alerting on anomalous CLI sessions — Pipe QUERY_HISTORY and ACCESS_HISTORY into your SIEM. Alert on unexpected GRANT, CREATE USER, COPY INTO @stage from CLI client sessions. Catches both this and any successor injection bug.
  4. Treat snowflake.yml and Snowflake project manifests as code — Require PR review, CODEOWNERS, and a semgrep/regex rule flagging suspicious $$, unbalanced quotes, or identifier separators in those files.
What doesn't work
  • Network ACLs / IP allowlists on Snowflake — the injected SQL rides the legitimate user's authenticated session from a permitted IP.
  • WAFs / NGFWs — there is no inbound network attack surface; the CLI is the attacker tool, not a victim service.
  • MFA on the Snowflake login — the victim has already authenticated; MFA is satisfied before the malicious CLI invocation.
06 · Verification

Crowdsourced verification payload.

Run on each developer laptop or CI runner that has Python/Snowflake CLI installed. Invoke as python3 check_cve_2026_13752.py — no privileges required beyond reading the local Python environment. For CI, wire it into your image-build pipeline.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# CVE-2026-13752 — Snowflake CLI SQL injection (<3.19)
# Exit codes: 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN / not installed
import sys, shutil, subprocess, re

FIXED = (3, 19, 0)

def parse(v):
    m = re.match(r'(\d+)\.(\d+)\.(\d+)', v.strip())
    return tuple(int(x) for x in m.groups()) if m else None

def get_version():
    # 1) Try the `snow` binary
    snow = shutil.which('snow')
    if snow:
        try:
            out = subprocess.check_output([snow, '--version'], text=True, stderr=subprocess.STDOUT, timeout=10)
            m = re.search(r'(\d+\.\d+\.\d+)', out)
            if m: return m.group(1), 'snow --version'
        except Exception:
            pass
    # 2) Fall back to pip metadata
    try:
        import importlib.metadata as md
        return md.version('snowflake-cli'), 'pip metadata'
    except Exception:
        try:
            import importlib.metadata as md
            return md.version('snowflake-cli-labs'), 'pip metadata (labs)'
        except Exception:
            return None, None

ver, src = get_version()
if ver is None:
    print('UNKNOWN: snowflake-cli not installed on this host')
    sys.exit(2)

parsed = parse(ver)
if parsed is None:
    print(f'UNKNOWN: could not parse version string {ver!r} ({src})')
    sys.exit(2)

if parsed < FIXED:
    print(f'VULNERABLE: snowflake-cli {ver} < 3.19.0 ({src})')
    sys.exit(1)
print(f'PATCHED: snowflake-cli {ver} ({src})')
sys.exit(0)
07 · Bottom Line

If you remember one thing.

TL;DR
This is a LOW for almost every shop — a local SQL-injection in a developer CLI that needs a trojaned input file and a willing victim. Per the noisgate mitigation SLA, LOW carries no mitigation deadline; per the noisgate remediation SLA, fold the snowflake-cli >= 3.19.0 bump into the normal dependency-refresh cycle (target within 365 days, but realistically the next CI image rebuild). Monday morning: pin snowflake-cli==3.19.0 in your CI base images, push a Slack/email note to data-engineering teams to pipx upgrade snowflake-cli, and — far more valuable than the patch itself — audit whether any CI service accounts run snow under ACCOUNTADMIN and demote them to scoped functional roles. That role-hygiene work pays down risk on this CVE and the next half-dozen Snowflake CLI bugs.

Sources

  1. Snowflake CLI 2026 release notes
  2. Snowflake Security Bulletins
  3. snowflake-cli on PyPI
  4. snowflake-cli GitHub releases
  5. OpenCVE — Snowflake vendor page
  6. CWE-89 — SQL Injection
  7. Snowflake CLI documentation
  8. Datadog — Threat hunting in Snowflake
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.