T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/main.ts:113
- Finding
- OS Command Injection Through the Input Image Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.ts:113-120` **Vulnerability Type**: OS command injection caused by unsafe shell interpolation **Risk Level**: High ### Complete Code Snippet ```typescript async function autoDetectResolution(inputImagePath: string, explicitResolution: "1K" | "2K" | "4K"): Promise<"1K" | "2K" | "4K"> { if (explicitResolution !== "1K") return explicitResolution; try { const { execSync } = await import("node:child_process"); const result = execSync(`identify -format "%w %h" "${inputImagePath}" 2>/dev/null`, { encoding: "utf8" }).trim(); const [w, h] = result.split(" ").map(Number); ``` ### Technical Analysis The user-controlled `inputImagePath` is interpolated directly into a command executed through `execSync`. Because `execSync` receives a string, Node.js invokes a shell to interpret it. Wrapping the path in double quotes does not prevent injection. A filename containing a double quote can terminate the quoted argument and introduce shell operators or additional commands. The earlier `access(args.inputImage)` check does not make the value safe; an attacker can create a file whose name contains shell metacharacters and then supply that exact path. This shell invocation is not necessary for the declared image-generation functionality. Image dimensions should be obtained through a library or by invoking `identify` without a shell. ### Attack Path 1. The attacker creates an accessible image file with a crafted filename containing a quote, shell separator, command, and comment marker. 2. The attacker supplies that path using `--input-image`. 3. The `access()` check succeeds because the crafted file exists. 4. With the default `1K` resolution, `autoDetectResolution()` is called. 5. The crafted path terminates the quoted shell argument. 6. The shell executes the injected command with the same operating-system privileges as the Skill process. ### Impact Assessment Successful exploitation provi ...[truncated 370 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Replace `execSync` with `execFile` or `spawn` and pass arguments as an array with shell processing disabled: ```typescript import { execFile } from "node:child_process"; import { promisify } from "node:util"; const execFileAsync = promisify(execFile); const { stdout } = await execFileAsync( "identify", ["-format", "%w %h", inputImagePath], { timeout: 30_000, maxBuffer: 1024 * 1024 } ); ``` - Prefer a maintained image-metadata library that does not invoke an external process. - Validate that the input is a regular file and impose a reasonable file-size limit before processing. - Do not attempt to make shell interpolation safe through manual escaping; eliminate the shell boundary entirely. - Run the Skill with minimal filesystem permissions and without access to unrelated credentials. ]]>
