T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- server.js:620
- Finding
- Unauthenticated disclosure of agent conversations and operational metadata<![CDATA[ ## Vulnerability Details **File Location**: `server.js:620-680`, `server.js:811-814` **Vulnerability Type**: Missing authentication, permissive CORS, and unrestricted WebSocket access **Risk Level**: High ### Vulnerable Code ```js if (req.url === '/api/state') { try { const data = await collectAllData(); res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify(data)); } catch (e) { res.writeHead(500); res.end(JSON.stringify({ error: e.message })); } return; } if (req.url.startsWith('/api/session-history?')) { const params = new URL(req.url, 'http://localhost').searchParams; const agent = params.get('agent'); const sessionId = params.get('sessionId'); res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Access-Control-Allow-Origin': '*' }); if (!agent || !sessionId) { res.end(JSON.stringify({ error: 'Missing agent or sessionId' })); return; } try { const jsonlPath = path.join( OPENCLAW_HOME, 'agents', agent, 'sessions', sessionId + '.jsonl' ); const content = fs.readFileSync(jsonlPath, 'utf8'); const lines = content.trim().split('\n'); const messages = []; for (const line of lines) { try { const entry = JSON.parse(line); const role = entry.role || (entry.message && entry.message.role); const rawContent = entry.content || (entry.message && entry.message.content); if ((role === 'user' || role === 'assistant') && rawContent) { let text = ''; if (typeof rawContent === 'string') { text = rawContent; } else if (Array.isArray(rawContent)) { for (const part of rawContent) { if (part.type === 'text' && part.text) { text += part.text + '\n'; } } } if (text.trim()) { ...[truncated 2853 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Generate a cryptographically random dashboard token at startup and require it on every API and WebSocket request. 2. Replace wildcard CORS with an explicit allowlist, such as the exact dashboard origin. 3. Validate the `Origin` header during WebSocket upgrades and reject unknown or absent origins. 4. Apply per-resource authorization so a caller can access only explicitly permitted agents and sessions. 5. Do not expose complete transcripts by default. Require an explicit, authenticated user action. 6. Minimize `/api/state` output by removing unnecessary hostname, session, and conversation fields. 7. Add security headers, including a restrictive Content Security Policy. 8. Treat localhost services as potentially reachable by hostile browser content and local processes. ]]>
