T09 · Insecure Skill Coding Practices
Error
- Location
- src/python-bridge/index.ts:14
- Finding
- Path Traversal Enables Execution of Arbitrary Local Python Scripts<![CDATA[ ## Vulnerability Details **File Location**: `src/python-bridge/index.ts:14-22` **Vulnerability Type**: Path traversal leading to local code execution **Risk Level**: High ### Vulnerable Code ```typescript export async function callPython( scriptName: string, input: PythonInput ): Promise<PythonOutput> { return new Promise((resolve, reject) => { const scriptPath = path.join(PYTHON_CORE_DIR, `${scriptName}.py`); const python = spawn('python3', [scriptPath, JSON.stringify(input)]); ``` ### Technical Analysis The exported `callPython` function accepts an unrestricted `scriptName` and constructs an executable path by joining that value with `PYTHON_CORE_DIR`. The value is not checked against an allowlist and the normalized path is not verified to remain inside the intended directory. Although `spawn` is used without a shell, which prevents conventional shell metacharacter injection, directory traversal remains possible. A value containing components such as `../../` can resolve to a Python file outside `python-core`. The resulting path is passed directly to the Python interpreter. The automatically appended `.py` suffix limits the target to Python files, but it does not prevent traversal or execution of attacker-selected scripts. ### Attack Path 1. An attacker obtains access to the exported `callPython` bridge, such as through application code that exposes it or permits arbitrary bridge calls. 2. The attacker supplies a traversal value such as `../../../../tmp/payload` as `scriptName`. 3. `path.join` normalizes the path outside `PYTHON_CORE_DIR`, resulting in a target such as `/tmp/payload.py`. 4. If that Python file exists and is readable, `spawn('python3', ...)` executes it. 5. The script runs with the operating-system identity and permissions of the Node.js process. Exploitation requires the attacker to control the `scriptName` argument and identify or place an executable Python file on the local filesystem. ### Impact Asses ...[truncated 423 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not expose a generic script execution function as part of the public bridge interface. - Replace caller-provided script names with a fixed allowlist mapping: ```typescript const SCRIPTS = { predict: path.join(PYTHON_CORE_DIR, 'predict.py') } as const; type ScriptName = keyof typeof SCRIPTS; ``` - Resolve and validate the final path before execution: ```typescript const coreDirectory = path.resolve(PYTHON_CORE_DIR); const scriptPath = path.resolve(coreDirectory, `${scriptName}.py`); if ( !scriptPath.startsWith(coreDirectory + path.sep) || !/^[a-zA-Z0-9_-]+$/.test(scriptName) ) { throw new Error('Invalid Python script name'); } ``` - Prefer dedicated functions that always invoke a hardcoded script rather than accepting any script name. - Run the subprocess as a restricted service account with minimal filesystem and network permissions. - Add tests covering `../`, absolute-path-like input, encoded traversal attempts, and unsupported script names. ]]>
