T09 · Insecure Skill Coding Practices
- Location
- index.ts:388
- Finding
- Gateway RPC Accepts an Unrestricted Transcript File Path<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:388-405` **Vulnerability Type**: Arbitrary local file access and file-existence probing **Risk Level**: High ### Vulnerable Code ```ts api.registerGatewayMethod('context-compactor.stats', async ({ params, respond }: any) => { try { const { sessionFile } = params; if (!sessionFile || !fs.existsSync(sessionFile)) { respond(true, { error: 'Session file not found', messages: 0, tokens: 0 }); return; } const entries = readTranscript(sessionFile); const messages = extractMessages(entries); const totalTokens = messages.reduce( (sum, m) => sum + estimateTokens(m.content, charsPerToken), 0 ); respond(true, { messages: messages.length, tokens: totalTokens, maxTokens, needsCompaction: totalTokens > maxTokens, cacheSize: summaryCache.size, }); ``` The invoked transcript reader performs a synchronous read of the supplied path: ```ts function readTranscript(sessionPath: string): SessionEntry[] { if (!fs.existsSync(sessionPath)) return []; const content = fs.readFileSync(sessionPath, 'utf8'); const lines = content.trim().split('\n').filter(Boolean); return lines.map(line => { try { return JSON.parse(line); } catch { return null; } }).filter(Boolean) as SessionEntry[]; } ``` ### Technical Analysis The gateway method takes `params.sessionFile` from its caller and passes it directly to `fs.existsSync` and `fs.readFileSync`. It does not resolve the path from a trusted session identifier, canonicalize it, restrict it to an approved transcript directory, reject symlinks, verify that it is a regular file, or limit its size. No authorization check for this gateway method is visible in the project. If an untrusted or insufficiently privileged client can invoke the method, it can cause the OpenClaw process to access any path readable with the process's filesystem privileges ...[truncated 1770 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not accept a filesystem path from the RPC caller. Accept a session identifier and resolve it through a trusted server-side session registry. - Require explicit authorization for the gateway method and verify that the caller may inspect the requested session. - Canonicalize both the approved transcript root and candidate file with `fs.realpath`. - Verify containment using a path-relative comparison that rejects paths resolving outside the approved root. - Reject symbolic links and all non-regular files. - Apply a strict maximum file size before reading. - Prefer bounded asynchronous or streaming reads instead of `readFileSync`. - Return the same generic response for nonexistent and unauthorized paths to reduce path-existence probing. - Add tests for absolute paths, `../` traversal, symlink escapes, device files, named pipes, and oversized files. ]]>
