T09 · Insecure Skill Coding Practices
Error
- Location
- S2_SPACE_ARCHITECT_MANUAL.md:64
- Finding
- Shell Command Injection in the Recommended Next.js API Bridge<![CDATA[ ## Vulnerability Details **File Location**: `S2_SPACE_ARCHITECT_MANUAL.md`, lines 64-75 **Vulnerability Type**: OS command injection through shell interpolation **Risk Level**: High ### Vulnerable Code ```typescript import { NextResponse } from 'next/server'; import { exec } from 'child_process'; import util from 'util'; import path from 'path'; const execAsync = util.promisify(exec); export async function POST(request: Request) { try { const { space } = await request.json(); const pythonScriptPath = path.join(process.cwd(), '../s2_space_parser/s2_parser_engine.py'); const { stdout, stderr } = await execAsync(`python3 ${pythonScriptPath} --space "${space}"`); ``` ### Technical Analysis The documented API route extracts `space` from an HTTP request and directly embeds it in a command string passed to `child_process.exec`. The `exec` API invokes a system shell, so shell metacharacters and command substitutions in `space` are interpreted by that shell. Wrapping the input in double quotes is not sufficient. Shell constructs such as command substitution remain active inside double quotes, and an attacker can also terminate the quoted argument before appending another command. The Python parser itself uses `argparse` safely, but the shell processes the command string before Python receives it. Consequently, validation performed by the Python program cannot prevent this vulnerability. ### Attack Path 1. A developer implements the Next.js route exactly as prescribed by the project manual. 2. The route is made reachable through the application, with no input validation shown in the example. 3. An attacker submits a POST request whose JSON `space` property contains shell syntax, such as command substitution or a quote followed by an additional command. 4. The route interpolates that value into the command string. 5. `execAsync` starts a system shell. 6. The shell evaluates the attacker-controlled syntax before launching, or alongside, the ...[truncated 1062 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Replace `exec` with `execFile` or `spawn` and pass arguments as an array without enabling a shell: ```typescript import { execFile } from 'child_process'; import util from 'util'; const execFileAsync = util.promisify(execFile); const { stdout, stderr } = await execFileAsync( 'python3', [pythonScriptPath, '--space', space], { timeout: 10_000, maxBuffer: 1024 * 1024, windowsHide: true } ); ``` - Verify that `space` is a string before using it. - Enforce a conservative maximum length. - Prefer an allowlist of supported room names if arbitrary fallback names are unnecessary. - Resolve the Python script to a trusted absolute path and verify that it is located under the expected application directory. - Run the API service under a dedicated, unprivileged operating-system account. - Add authentication, authorization, request-size limits, rate limiting, and structured security logging to the route. - Return generic client errors rather than exposing raw process error messages. - Add automated tests containing quotes, semicolons, command substitutions, newlines, and platform-specific shell metacharacters. ]]>
