Skip to Content
VulnerabilitiesCode Injection

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() or exec() with untrusted input
  • pickle.loads() with untrusted data
  • yaml.load() without Loader=yaml.SafeLoader
  • subprocess.run(..., shell=True) with user input

Remediation Checklist

  1. Avoid dynamic code execution - Use configuration or DSLs instead
  2. Sandbox execution - Use containers, VMs, or restricted Python environments
  3. Allowlist operations - Only permit specific, known-safe operations
  4. Validate LLM output - Parse and validate before any execution
  5. Use safe serialization - JSON, MessagePack, or Protobuf instead of Pickle
Last updated on