T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/server.js:20
- Finding
- Filesystem storage is created outside the documented project boundary<![CDATA[ ## Vulnerability Details **File Location**: `scripts/server.js`, lines 20–28 **Vulnerability Type**: Incorrect filesystem root resolution **Risk Level**: High ### Vulnerable Code ```js const ROOT = path.resolve(__dirname, '..', '..', '..'); // repo root const BASE = path.join(ROOT, 'stdio'); const BOXES = { inbox: path.join(BASE, 'inbox'), outbox: path.join(BASE, 'outbox'), tmp: path.join(BASE, 'tmp'), }; for (const p of Object.values(BOXES)) fs.mkdirSync(p, { recursive: true }); ``` ### Technical Analysis The server claims that `ROOT` is the repository root, but it traverses three parent directories from `scripts/server.js`. Under the audited project layout, the script is located at: ```text /tmp/clawhub-codex-scan-v57axzqee6rxhth9q50v4f5be58e4144-8BV93k/artifact/scripts/server.js ``` Resolving three parent components from `artifact/scripts` produces `/tmp`, rather than the `artifact` project directory. Consequently, the server creates and operates on these predictable shared paths: ```text /tmp/stdio/inbox /tmp/stdio/outbox /tmp/stdio/tmp ``` This behavior contradicts the workspace-relative storage model documented in `SKILL.md`. It also eliminates project-level isolation: other instances, projects, or processes running with sufficient permissions can interact with the same file boxes. The directories are created without explicit restrictive permission modes. Their effective permissions therefore depend on the process umask and any pre-existing `/tmp/stdio` directory. ### Attack Path 1. The MCP server starts and resolves `ROOT` to `/tmp`. 2. It creates or reuses `/tmp/stdio/inbox`, `/tmp/stdio/outbox`, and `/tmp/stdio/tmp`. 3. Another local process running as the same account, or otherwise having access to those directories, places a file in one of the shared boxes. 4. The Skill lists or reads that file as if it belonged to the current project. 5. Through the exposed tools, the file can be read, overwritten, moved, or deleted. 6. Co ...[truncated 776 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Resolve the storage root from the actual project directory. Given the audited layout, use: ```js const ROOT = path.resolve(__dirname, '..'); const BASE = path.join(ROOT, 'stdio'); ``` Additional hardening should include: 1. Create project-specific storage directories rather than a predictable globally shared directory. 2. Set restrictive permissions explicitly: ```js for (const p of Object.values(BOXES)) { fs.mkdirSync(p, { recursive: true, mode: 0o700 }); fs.chmodSync(p, 0o700); } ``` 3. Refuse to use a pre-existing base directory unless its owner and permissions are trusted. 4. Verify at startup that the canonical `BASE` path is inside the expected canonical project root. 5. Avoid returning absolute host paths through `stdio_paths` unless disclosure is operationally necessary. 6. Add a regression test asserting that every box path remains beneath the project root. ]]>
