Description
Treat LLM output as untrusted input to downstream systems, regardless of model alignment or prompt instructions. Prompt injection, ordinary requests, retrieved content or model errors can produce unexpected commands. Passing that output to a system shell indirectly gives the model command-execution authority.
The actual risk depends on input sources, process permissions, the execution environment, and separate authorization and confirmation controls. Validating output as data is different from authorizing the operation it describes.
Potential impact
- Passing generated text to
execorexecSynclets the shell interpret metacharacters and additional arguments, potentially causing command injection. - An attacker may execute commands or call other programs and scripts with the application's permissions.
- Access to files, credentials, databases or deployment permissions can extend the impact to data exposure, modification or service disruption.
Remediation
- Do not execute free-form commands returned by a model. Prefer an in-process library or a fixed application operation map.
- Treat structured output as untrusted too. JSON schemas validate shape; deterministic application code must separately check allowed operations, arguments, targets and user permissions.
- Prefer library APIs for operating-system functions. If a subprocess is necessary, fix the executable in code, validate each argument, pass an argument array to
execFileorspawn, and disable the shell. Escaping a complete generated command or naming a helpersanitizedoes not establish safety. - Require confirmation of the exact operation for privileged, irreversible or externally consequential actions, and give the model-connected process only the permissions it needs.
- Retest direct and indirect prompt injection and malformed outputs when models, prompts, tools or output schemas change.
Examples
Before
import OpenAI from "openai";
import { exec } from "node:child_process";
const client = new OpenAI();
async function runGeneratedCommand(userRequest) {
const response = await client.responses.create({
model: "gpt-5.5",
input: `Write a shell command for this request: ${userRequest}`
});
exec(response.output_text);
}
After
import OpenAI from "openai";
const client = new OpenAI();
const ALLOWED_TARGETS = new Set(["api-staging", "worker-staging"]);
const OPERATIONS = Object.freeze({
status: target => getDeploymentStatus(target)
});
function parseAction(text) {
const value = JSON.parse(text);
if (
!value ||
typeof value !== "object" ||
typeof value.operation !== "string" ||
typeof value.target !== "string" ||
!Object.hasOwn(OPERATIONS, value.operation) ||
!ALLOWED_TARGETS.has(value.target)
) {
throw new Error("Unsupported model action");
}
return value;
}
async function runAllowedAction(userRequest) {
const response = await client.responses.create({
model: "gpt-5.5",
input: `Choose a read-only operation for: ${userRequest}`
});
const action = parseAction(response.output_text);
return OPERATIONS[action.operation](action.target);
}
Explanation:
- Before: Generated text goes directly to
exec(...), allowing the shell to interpret metacharacters and additional commands. - After: The model can select only predefined read-only operations and targets; its output is not executed.
getDeploymentStatusand error handling are omitted. Separately verify that the current user may access the selected target.
Other output contexts
Output sent to HTML or Markdown, SQL, file paths or terminals also requires handling appropriate to that context. Prefer text output and context-specific encoding for HTML; use an HTML sanitizer such as DOMPurify when markup is necessary. Use native Element.setHTML() only after confirming runtime support, and do not treat setHTMLUnsafe() as a general remedy.
References
- OWASP Top 10 for LLM Applications 2026
- OWASP LLM05:2025 Improper Output Handling
- CWE-1426: Improper Validation of Generative AI Output
- CWE-78: Improper Neutralization of Special Elements used in an OS Command
- Node.js 24 LTS
child_processdocumentation - OWASP OS Command Injection Defense Cheat Sheet
- OWASP Cross Site Scripting Prevention Cheat Sheet
- MDN
Element.setHTML() - DOMPurify guidance
- OpenAI JavaScript/TypeScript SDK
- Anthropic TypeScript SDK