CVE-2026-13749
Snowflake CLI allows code execution via malicious Snowpark project content.
- CVSS 8.8
- CWE-94
- Input Validation and Sanitization
- Local
Improper neutralization in the Snowpark annotation processor callback template in Snowflake CLI versions prior to 3.19 allowed arbitrary code execution during application bundling or deployment. An attacker could exploit this by supplying crafted project content that is interpolated into generated Python code, causing Snowflake CLI to execute attacker-controlled code in the local context of the user running the CLI. Successful exploitation requires the victim to run the relevant bundling or deployment workflow against attacker-controlled project content, and any resulting code runs with the privileges of that local execution context. The fix is available in Snowflake CLI version 3.19, and users must manually upgrade.
- CWE
- CWE-94
- CVSS base score
- 8.8
- Published
- 2026-06-29
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Build/Package/Merge
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Command Injection
- Accessibility scope
- Local
- Impact
- Arbitrary Code Execution
- Affected component
- Snowflake CL
- Fixed by upgrading
- Yes
Solution
Upgrade Snowflake CLI to version 3.19.
Vulnerable code sample
def generate_callback_script(project_config: dict) -> str:
"""
This function represents the vulnerable logic where user-controlled
project content is improperly interpolated into a Python code template
without sanitization, leading to code injection.
"""
# The 'callback_name' is read from a user-controlled configuration file.
callback_name = project_config.get("callback_function_name")
# VULNERABLE STEP: The user-provided 'callback_name' is directly
# embedded into the f-string. An attacker can inject newlines and
# arbitrary Python code by crafting a malicious function name.
generated_code = f"""
# --- Auto-generated deployment script ---
import sys
def {callback_name}():
# This function is intended to be a user-defined callback.
print("Executing post-deployment callback...")
# The CLI workflow would execute the generated function.
if __name__ == "__main__":
{callback_name}()
"""
# The returned string containing the generated code would then be
# executed by the CLI in the user's local environment.
return generated_codePatched code sample
import re
def generate_safe_deployment_script(project_config: dict) -> str:
"""
Generates a deployment script, safely handling user-provided callback names.
This function represents the fix for a vulnerability where a user-provided
value (callback_name) was unsafely interpolated into a code template.
The fix involves validating that the 'callback_name' is a valid Python
identifier before incorporating it into the generated code. This prevents
arbitrary code from being injected.
"""
callback_name = project_config.get("callback_name")
if not callback_name:
raise ValueError("'callback_name' not found in project configuration.")
# --- THE FIX ---
# Validate that the callback_name is a simple, valid Python identifier.
# This prevents injection of arbitrary code constructs like function calls
# or import statements.
if not re.fullmatch(r"[a-zA-Z_][a-zA-Z0-9_]*", callback_name):
raise ValueError(
f"Invalid callback name: '{callback_name}'. "
"Name must be a valid Python identifier to prevent code injection."
)
# --- END OF FIX ---
# The validated 'callback_name' can now be safely used in the template.
generated_code = f"""
# Dynamically generated deployment script
import os
print("Starting deployment process...")
def {callback_name}():
# This is a placeholder for the user's actual callback function
print(f"Executing validated user callback: '{callback_name}'")
print(f"Running as user: {{os.getenv('USER', 'unknown')}}")
# Execute the callback
{callback_name}()
print("Deployment process finished.")
"""
return generated_code
if __name__ == '__main__':
# --- DEMONSTRATION ---
# 1. Benign project configuration (works as expected)
benign_config = {
"app_name": "my_app",
"callback_name": "run_custom_setup"
}
print("--- Testing with benign configuration ---")
try:
safe_script = generate_safe_deployment_script(benign_config)
print("Generated script is safe. Simulating execution:")
# In a real scenario, this script would be saved and executed.
# We use exec() here for demonstration purposes only.
exec(safe_script)
except ValueError as e:
print(f"Error: {e}")
print("\n" + "="*40 + "\n")
# 2. Malicious project configuration (is blocked by the fix)
# The old, vulnerable version would have interpolated this directly,
# leading to os.system('echo pwned') being executed.
malicious_config = {
"app_name": "my_app",
"callback_name": "print('hello')\nimport os\nos.system('echo PWNED BY CVE-2026-13749')"
}
print("--- Testing with malicious configuration ---")
try:
generate_safe_deployment_script(malicious_config)
except ValueError as e:
print("Successfully blocked malicious input.")
print(f"Caught expected error: {e}")Payload
definition_version: 1
snowpark:
project_name: 'exploit"; import os; os.system("touch /tmp/pwned"); "'
stage_name: dev
src: app/
Cite this entry
@misc{vaitp:cve202613749,
title = {{Snowflake CLI allows code execution via malicious Snowpark project content.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-13749},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-13749/}}
}
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 ::
