T09 · Insecure Skill Coding Practices
Error
- Location
- src/server.js:115
- Finding
- Unauthenticated API Endpoints Act as a Privileged OpenClaw Gateway Proxy<![CDATA[ ## Vulnerability Details **File Location**: `src/server.js:115-145`, `src/server.js:211-238` **Vulnerability Type**: Missing authentication and authorization on credential-backed proxy endpoints **Risk Level**: High when exposed beyond localhost; Medium under the default loopback-only configuration ### Vulnerable Code ```js // POST /api/chat-stream { messages } → sentence-level SSE // Each SSE event: data: {"sentence":"...", "done":false} or {"done":true,"fullText":"..."} app.post('/api/chat-stream', async (req, res) => { if (!OPENCLAW_GATEWAY_TOKEN) { return res.status(500).json({ ok: false, error: 'OPENCLAW_GATEWAY_TOKEN not set' }); } let messages; if (req.body?.messages?.length) { messages = req.body.messages; } else { const text = String(req.body?.text || '').trim(); if (!text) return res.status(400).json({ ok: false, error: 'text or messages required' }); messages = [{ role: 'user', content: text }]; } // SSE headers res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.flushHeaders(); const sendEvent = (obj) => res.write(`data: ${JSON.stringify(obj)}\n\n`); try { const upstream = await fetch(`${OPENCLAW_GATEWAY_URL}/v1/chat/completions`, { method: 'POST', headers: { 'Authorization': `Bearer ${OPENCLAW_GATEWAY_TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: OPENCLAW_MODEL, user: 'voiceclaw', messages, stream: true }), }); ``` The non-streaming endpoint has the same access-control issue: ```js // POST /api/chat { text } → OpenClaw Gateway → { reply } app.post('/api/chat', async (req, res) => { try { if (!OPENCLAW_GATEWAY_TOKEN) { return res.status(500).json({ ok: false, error: 'OPENCLAW_GATEWAY_TOKEN not set' }); } // Accept { messages } (full history) or { text } (single turn) let messages; if (req.b ...[truncated 3780 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require authentication and authorization for every `/api/*` endpoint. Use a separate application session credential rather than exposing a bearer-token-backed proxy to anonymous clients. 2. Generate a dedicated, least-privilege OpenClaw credential for voiceclaw. Restrict it to only the model and operations required for voice conversation. 3. Keep loopback binding as the default and fail closed if a non-loopback `HOST` is configured without explicit authentication and TLS settings. 4. For remote deployments, require HTTPS, an authenticated reverse proxy, restrictive firewall rules, and trusted-client access controls. 5. Validate `messages` as an array of bounded objects with explicitly permitted roles and string content. Reject unknown properties, excessive message counts, and oversized content. 6. Validate and bound TTS text and speaker parameters. 7. Add per-client rate limiting, concurrency limits, upstream timeouts, and response-size limits. 8. Apply restrictive CORS and origin checks as defense in depth, while not treating origin checks as a substitute for authentication. 9. Document that changing `HOST` or publishing the port crosses a security boundary and is unsafe without access controls. ]]>
