๐ What Is It?
Improper Output Handling is the insufficient validation, sanitization, and encoding of the text a model produces before it reaches another component. The bug is not in the model โ it is in the code that consumes the output and treats it as trusted. The mental model: treat every token an LLM emits as untrusted user input. If that output flows into a browser, shell, SQL query, HTTP client, file path, or eval(), the attacker has reached across the model into your downstream system. (Renamed from 2023's LLM02: Insecure Output Handling.)
โ ๏ธ Top Attack Vectors
- Reflected / stored XSS: output placed in the DOM via
innerHTML - Markdown image/link exfiltration: auto-loaded URL leaks data (zero-click)
- SQL / NoSQL injection: output concatenated into a query
- OS command injection: output passed through a shell
- Code execution via eval/exec: output run as code (highest severity)
- SSRF: server fetches a model-supplied URL (cloud metadata, internal)
- Path traversal & SSTI: output builds a file path or template source
- Agent tool abuse: free-form output selects tool + arguments
๐ฏ Every Bug Has 3 Conditions
1. INFLUENCE โ attacker shapes the output (direct or indirect injection).
2. FLOW โ output reaches a sink without context-appropriate encoding/parameterization.
3. SINK โ the sink interprets structure: browser parses HTML/JS, DB parses SQL, shell parses metacharacters, eval() parses code.
You can't remove (1) โ models are influenceable by design โ so defenders concentrate on the handoff (2) and constrain the sink (3).
๐ด Attack Flow
โ
2. EMIT: model produces output containing a payload (script, SQL, URL, code)
โ
3. EXECUTE: a vulnerable sink interprets the payload
โ
4. IMPACT: XSS, data exfiltration, SSRF, or remote code execution
โ Vulnerable Code
โ Secure Code
โ Prevention Checklist
- Treat model output as untrusted input everywhere it crosses a boundary
- Context-encode for the exact sink (HTML body/attr, JS, URL, CSS, SQL, shell)
- Parameterize all DB calls; bind output as values only
- Never pass output to
eval/exec/os.system/deserializers; sandbox any code - Sanitize Markdown/HTML with a strict allow-list; serve a restrictive CSP
- Allow-list model-supplied URLs (scheme + host) before any fetch (SSRF)
- Canonicalize file paths with a base-directory containment check
- Schema-validate + allow-list agent tool arguments; least-privilege creds
- Human approval for high-impact actions; log output that triggers side effects
๐งฐ Tools & Takeaway
"It came from our own AI" is provenance, not integrity. Guardrails target harmful meaning; a benign-looking sentence can still carry </script>, a SQL quote, or a shell metacharacter. Deterministic encoding/parameterization at the sink is what actually stops the exploit โ mark the model client as an appsec source and your XSS/SQLi/SSRF tooling lights up.