T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/s2g-bridge.js:257- Finding
Unauthenticated Privileged Workflow API Exposed on All Network Interfaces
- Content
View full analysis
{ const url = new URL(req.url, `http://localhost:${HTTP_PORT}`); const p = url.pathname; res.setHeader('Content-Type', 'application/json'); res.setHeader('Access-Control-Allow-Origin', '*'); if (req.method === 'OPTIONS') { res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); res.statusCode = 204; res.end(); return; } if (req.method === 'GET' && p === '/status') { res.end(JSON.stringify({ connected, s2gHost: S2G_WS_HOST, nodeId: NODE_ID, lastConnected, lastError, stats, pendingRequests: pendingRequests.size, nodes: availableNodes.map(n => ({ name: n.name, type: n.nodeType, id: n.nodeId, outputs: n.outputParams })) }, null, 2)); return; } if (req.method === 'GET' && p === '/nodes') { res.end(JSON.stringify({ connected, nodes: availableNodes }, null, 2)); return; } if (req.method === 'POST' && p === '/execute') { const body = await readBody(req); if (!body.nodeId) { res.statusCode = 400; res.end(JSON.stringify({ error: 'Missing nodeId' })); return; } const result = await executeNode(body.nodeId, body.params || {}, body.timeout || DEFAULT_TIMEOUT); res.end(JSON.stringify(result, null, 2)); return; } if (req.method === 'POST' && p.startsWith('/execute/')) { const name = decodeURIComponent(p.slice('/execute/'.length)); const node = findNode(name); if (!node) { res.statusCode = 404; res.end(JSON.stringify({ error: `Node "${name}" not found`, available: availableNodes.map(n => n.name) })); return; } const body = await readBody(req); const params = body ...[truncated 2499 chars]- Remediation
View remediation
{ // ... }); ``` 2. Require a cryptographically strong bearer token or use a Unix-domain socket. Compare tokens using a timing-safe comparison. 3. Do not reuse the S2G WebSocket secret as the local API credential. 4. Require an explicit option such as `--allow-remote` before accepting non-loopback bindings. 5. Add per-node authorization or an allowlist so callers cannot execute every discovered node. 6. Disable high-impact nodes by default, particularly database, cloud, HTTP, scripting, and destructive knowledge-base operations. 7. Apply firewall rules as defense in depth, not as the primary access-control mechanism. 8. Return minimal information from `/status` and `/nodes` to unauthenticated health checks. ]]>
