{"$schema":"https://failmodes.com/schema/failure-mode.schema.json","taxonomyVersion":"0.0.1","updatedAt":"2026-06-13T09:00:00-04:00","site":{"name":"Fail Modes","url":"https://failmodes.com/"},"failureMode":{"id":"insecure-output-handling","version":"0.0.1","updatedAt":"2026-06-13T09:00:00-04:00","name":"Insecure Output Handling","description":"Produces output that is unsafe for downstream rendering, execution, storage, parsing, logging, or human trust without sanitization or validation.\n\nUnlike Unsafe Tool Call, the risk is in what the model emits for another system or person to handle. Unlike Supply Chain Vulnerability, the risk does not necessarily come from a dependency or upstream package.","shortDefinition":"Produces output that is unsafe for downstream rendering, execution, storage, parsing, logging, or human trust without sanitization or validation.","status":"published","url":"https://failmodes.com/failure-modes/insecure-output-handling","jsonUrl":"https://failmodes.com/failure-modes/insecure-output-handling.json","markdownUrl":"https://failmodes.com/failure-modes/insecure-output-handling.md","hasStructuredContent":true,"searchPhrases":["output wasn't sanitized","unsafe output for downstream","emitted unsafe markup","output could be executed"],"category":{"id":"security","name":"Security","blurb":"Manipulation, leaks, unsafe behavior","url":"https://failmodes.com/browse?category=security"},"detail":{"why":["Training corpora are full of insecure patterns. Code with injection flaws, unescaped templates, and unsafe deserialization is abundant in public repositories, and the model reproduces what was common, not what was safe (Pearce et al., 2022, \"Asleep at the Keyboard? Assessing the Security of GitHub Copilot's Code Contributions\").","The model generates text without a model of the execution sink. Whether output lands in a terminal, an HTML page, a SQL query, or a log file is invisible at generation time, so it cannot apply the escaping discipline each sink requires.","Model output inherits unearned trust downstream. Because it comes from inside the application rather than from a user, developers pipe it into renderers, shells, and interpreters without the sanitization they would apply to user input (OWASP, 2025, \"LLM05: Improper Output Handling\").","Untrusted input flows through generation. Injection payloads in user input or retrieved content can be echoed into the output, turning the model into a laundering step that delivers attacker content past filters aimed only at direct input."],"examples":[{"kind":"fail","label":"Unescaped user input in HTML","text":"The model interpolates user-controlled data straight into markup, producing a cross-site scripting sink.","quote":"User: Write a Flask route that greets the user by the name query param.\nAssistant: return f\"<h1>Hello {request.args['name']}</h1>\""},{"kind":"fail","label":"String-built SQL query","text":"The generated query concatenates input instead of parameterizing it, creating an injection path downstream.","quote":"User: Look up a user by email in our SQLite db.\nAssistant: cur.execute(\"SELECT * FROM users WHERE email = '\" + email + \"'\")"},{"kind":"ok","label":"Escapes and parameterizes","text":"The output is shaped for its sink, with templating that escapes by default and a bound query parameter.","quote":"User: Write a Flask route that greets the user by the name query param.\nAssistant: return render_template(\"hello.html\", name=request.args.get(\"name\", \"\"))"}],"detection":[{"icon":"🔎","heading":"Static analysis scanning","body":"Run generated code through SAST rules and security linters before it ships. String-concatenated SQL, unescaped interpolation into markup, and unsafe deserialization are exactly the patterns these tools were built to flag — model output just needs to be routed through them like any other untrusted code."},{"icon":"🔬","heading":"Sandboxed execution","body":"Execute or render the generated code against canonical attack inputs — a name parameter of <script>alert(1)</script>, an email of ' OR 1=1 --. The f-string greeting either escapes the payload or executes it; the sandbox turns the vulnerability from a code-review judgment into an observed behavior."},{"icon":"⚖️","heading":"LLM-as-judge evaluation","body":"Ask the judge to identify the sink each output feeds — HTML, SQL, shell, logs — and whether the escaping discipline matches it. Also have it trace untrusted input through the output, since a payload echoed from the prompt into generated markup is laundered injection the sink-level check alone can miss."},{"icon":"🧪","heading":"Golden-set evals","body":"Maintain prompts known to elicit insecure patterns, organized by CWE, and score the incidence of each vulnerability class — never whether the code runs. Functional tests pass injectable code by design, which is exactly how these outputs survive every other check."}],"mitigation":[{"icon":"🧯","heading":"Sink-aware sanitization","body":"Treat model output as untrusted input at every boundary it crosses — escape before rendering, parameterize before querying, validate before parsing or executing. The unearned trust is the vulnerability's enabler; applying the same discipline used for user input means the f-string greeting's payload is neutralized even when generation got it wrong."},{"icon":"📝","heading":"Instruction constraints","body":"Tell the model the sink — \"this lands in HTML,\" \"this builds a SQL query\" — and require the matching discipline by default: templating that escapes, bound parameters, no string-built queries even in examples. Quick-start brevity trained the defensive code out; the prompt has to put it back in as non-optional."},{"icon":"🔁","heading":"Validate-and-retry loops","body":"Run generated code through SAST rules and security linters in the scaffold and bounce flagged output back with the finding named — \"string-concatenated SQL at line 3, parameterize it.\" Functional checks pass injectable code by design, so the security gate has to be a separate, blocking pass."}],"related":[{"id":"unsafe-tool-call","name":"Unsafe Tool Call","url":"https://failmodes.com/failure-modes/unsafe-tool-call","jsonUrl":"https://failmodes.com/failure-modes/unsafe-tool-call.json"},{"id":"supply-chain-vulnerability","name":"Supply Chain Vulnerability","url":"https://failmodes.com/failure-modes/supply-chain-vulnerability","jsonUrl":"https://failmodes.com/failure-modes/supply-chain-vulnerability.json"},{"id":"json-schema-failure","name":"JSON/Schema Failure","url":"https://failmodes.com/failure-modes/json-schema-failure","jsonUrl":"https://failmodes.com/failure-modes/json-schema-failure.json"}]}}}