Code Injection
Code injection vulnerabilities occur when LLM-generated or user-controlled code is executed without proper validation, allowing arbitrary code execution.
Code injection vulnerabilities are consistently rated CRITICAL (CVSS 9.8) as they can lead to complete system compromise.
Tainted Eval (CRITICAL)
CVSS 9.8 | CWE-94, CWE-95 | OWASP LLM02, LLM04
LLM-generated or user-controlled code executed via eval(), exec(), or equivalent functions.
Vulnerable
LLM output directly executed - attacker can run any code
def calculate(user_query):
# Ask LLM to generate Python code
code = llm.invoke(f"Write Python to: {user_query}")
# CRITICAL: Direct execution of LLM output
result = eval(code)
return result
# Attacker: "Calculate 1+1; also run __import__('os').system('rm -rf /')"Secure
Sandboxed execution with restricted builtins
import ast
SAFE_NODES = {ast.Expression, ast.BinOp, ast.Num, ast.Add, ast.Sub}
def safe_eval(code):
try:
tree = ast.parse(code, mode='eval')
for node in ast.walk(tree):
if type(node) not in SAFE_NODES:
raise ValueError(f"Unsafe operation: {type(node)}")
return eval(compile(tree, '<string>', 'eval'), {"__builtins__": {}})
except:
raise ValueError("Invalid expression")
def calculate(user_query):
code = llm.invoke(f"Write safe math expression for: {user_query}")
return safe_eval(code)Compliance:
- EU AI Act: Article 14 (Human Oversight), Article 15 (Cybersecurity)
- OWASP LLM: LLM02 (Insecure Output Handling)
Unvalidated Exec/Eval (CRITICAL)
CVSS 9.8 | CWE-78, CWE-94 | OWASP LLM02
Command execution, subprocess calls, or code evaluation without input validation.
Vulnerable
User input passed to subprocess
import subprocess
def run_tool(tool_name, args):
# User controls tool_name and args
cmd = f"{tool_name} {args}"
return subprocess.run(cmd, shell=True, capture_output=True)
# Attacker: tool_name="ls; cat /etc/passwd #"Secure
Allowlist validation before execution
import subprocess
import shlex
ALLOWED_TOOLS = {"grep", "wc", "head", "tail"}
def run_tool(tool_name, args):
if tool_name not in ALLOWED_TOOLS:
raise ValueError(f"Tool not allowed: {tool_name}")
# Use list form to prevent injection
safe_args = shlex.split(args)
return subprocess.run(
[tool_name] + safe_args,
shell=False, # Never use shell=True
capture_output=True
)Unsafe Pickle Deserialization (CRITICAL)
CVSS 9.8 | CWE-502
Untrusted data deserialized via pickle allowing arbitrary code execution.
Vulnerable
Pickle can execute arbitrary code on load
import pickle
def load_agent_state(data):
# CRITICAL: Pickle can execute arbitrary code
return pickle.loads(data)
def save_agent_state(state):
return pickle.dumps(state)Secure
Use safe JSON serialization
import json
from dataclasses import dataclass, asdict
@dataclass
class AgentState:
messages: list
context: dict
def load_agent_state(data):
parsed = json.loads(data)
return AgentState(**parsed)
def save_agent_state(state):
return json.dumps(asdict(state))Unsafe YAML Loading (CRITICAL)
CVSS 9.8 | CWE-502
YAML loaded with unsafe options allowing arbitrary code execution.
Vulnerable
yaml.load() can execute Python code
import yaml
def load_config(config_path):
with open(config_path) as f:
# CRITICAL: yaml.load() can execute arbitrary Python
return yaml.load(f)
# Malicious YAML:
# !!python/object/apply:os.system ['rm -rf /']Secure
Always use safe_load()
import yaml
def load_config(config_path):
with open(config_path) as f:
# safe_load() only allows basic YAML types
return yaml.safe_load(f)Never use:
eval()orexec()with untrusted inputpickle.loads()with untrusted datayaml.load()withoutLoader=yaml.SafeLoadersubprocess.run(..., shell=True)with user input
Remediation Checklist
- Avoid dynamic code execution - Use configuration or DSLs instead
- Sandbox execution - Use containers, VMs, or restricted Python environments
- Allowlist operations - Only permit specific, known-safe operations
- Validate LLM output - Parse and validate before any execution
- Use safe serialization - JSON, MessagePack, or Protobuf instead of Pickle
Last updated on