T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/generate.mjs:10
- Finding
- Output Root Resolves Outside the Project Boundary<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.mjs:10` **Vulnerability Type**: Incorrect output-directory trust boundary **Risk Level**: High ### Vulnerable Code ```js const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const WORKSPACE_ROOT = path.resolve(__dirname, '../../..'); ``` ### Technical Analysis The script derives its trusted output directory by ascending three levels from `scripts/generate.mjs`. In the audited layout, the script is located at: ```text /tmp/clawhub-codex-scan-v576b2egb8w4qfqmjwj50d0bms8e55pa-X9DIvx/artifact/scripts/generate.mjs ``` Resolving `../../..` from the `scripts` directory produces `/tmp`, rather than the project directory or a dedicated workspace directory. Subsequent path validation consistently trusts this incorrectly calculated value, so those checks do not restore the intended project boundary. Although `sanitizeOutputPath()` strips directory components and restricts extensions, it still permits writes to direct children of `/tmp`. This contradicts the documented claim that generated files are restricted to the workspace root. ### Attack Path 1. An attacker or untrusted caller invokes the generator with a controlled output name: ```bash node scripts/generate.mjs "attacker-controlled content" -o target.svg ``` 2. The script strips path components from `target.svg` and resolves it beneath `WORKSPACE_ROOT`. 3. Because `WORKSPACE_ROOT` resolves to `/tmp`, the resulting path is `/tmp/target.svg`. 4. If the process has sufficient filesystem permission, the script creates or replaces that file outside the project boundary. 5. The attacker can repeat this for files with one of the permitted extensions: `.svg`, `.png`, `.jpg`, or `.jpeg`. ### Impact Assessment The vulnerability grants write access beyond the project’s legitimate output directory. Its scope is limited to direct children of the incorrectly selected ancestor directory, approved ...[truncated 700 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not derive a security boundary by ascending a fixed number of parent directories. - Obtain the actual workspace path from a trusted runtime configuration value or explicitly use the project root: ```js const PROJECT_ROOT = path.resolve(__dirname, '..'); ``` - Prefer a dedicated output directory with restrictive permissions: ```js const OUTPUT_ROOT = path.join(PROJECT_ROOT, 'output'); fs.mkdirSync(OUTPUT_ROOT, { recursive: true, mode: 0o700 }); ``` - Resolve the destination against that exact directory and retain the `path.relative()` containment check. - Resolve the configured output root through `fs.realpathSync()` before trusting it, ensuring that the directory itself is not a symlink to another location. - Add a startup assertion that rejects unexpectedly broad directories such as `/`, `/tmp`, or a user home directory unless explicitly authorized. - Add automated tests that verify generated files remain inside the intended project or workspace directory for the deployed directory layout. ]]>
