T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/server.js:86
- Finding
- Unauthenticated LAN Clients Can Read, Replace, and Control Teleprompter Sessions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/server.js`, lines 86–111 **Vulnerability Type**: Missing authentication, pairing enforcement, origin validation, and role-based authorization **Risk Level**: High ### Vulnerable Code ```js wss.on('connection', (ws) => { clients.set(ws, { role: 'main' }); // default role ws.send(JSON.stringify({ type: 'state', ...state })); ws.on('message', (raw) => { try { const msg = JSON.parse(raw); if (msg.type === 'register') { clients.set(ws, { role: msg.role || 'main' }); broadcastRemoteCount(); } else if (msg.type === 'sync') { // Main teleprompter syncs state state = { idx: msg.idx, total: msg.total, current: msg.current || '', next: msg.next || '' }; broadcast({ type: 'state', ...state }, ws); } else if (msg.type === 'cmd') { // Remote sends command → broadcast to all (main will handle) broadcast({ type: 'cmd', action: msg.action }, ws); } else if (msg.type === 'text') { // Remote uploaded text → broadcast to all broadcast({ type: 'text', text: msg.text }, ws); } else if (msg.type === 'fulltext') { // Main syncs text to remotes broadcast({ type: 'fulltext', text: msg.text }, ws); } } catch {} }); ``` The network exposure is established at `scripts/server.js`, lines 117–124: ```js server.listen(PORT, '0.0.0.0', () => { console.log(`\n🎬 ClawPrompt Server`); console.log(` 电脑提词器: http://localhost:${PORT}`); console.log(` 手机遥控: http://${lanIP}:${PORT}/remote`); console.log(` (确保手机和电脑在同一 WiFi)\n`); }); ``` ### Technical Analysis The server listens on every network interface and accepts all WebSocket connections without credentials or a cryptographically random pairing token. The QR code only communicates the service URL; scanning it does not establish a trusted pairing relationship. A newly connected client immediately receives the current shared ...[truncated 1782 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Generate a cryptographically random, high-entropy pairing token for each session. 2. Include the token in the QR URL and require it during the WebSocket upgrade or an authenticated registration handshake. 3. Reject unauthenticated connections before sending any state. 4. Maintain server-assigned roles rather than accepting arbitrary client-provided roles. 5. Enforce message-level authorization: - Only the authenticated main display may send `sync` and `fulltext`. - Only approved remote clients may send `cmd` and `text`. 6. Validate the WebSocket `Origin` header against an explicit allowlist of expected local origins. 7. Require explicit approval on the main display before activating a newly paired remote. 8. Isolate independent sessions instead of placing all clients into one global broadcast group. 9. Use HTTPS and WSS where scripts may contain confidential information or the network cannot be fully trusted. 10. Bind only to localhost by default and require an explicit option before exposing the service to the LAN. ]]>
