T09 · Insecure Skill Coding Practices
- Location
scripts/bridge-server.mjs:126- Finding
Unauthenticated Network-Accessible Arbitrary Code Execution in the EasyEDA Bridge
- Content
View full analysis
{ // CORS res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); ``` ```javascript // lines 190-215 if (req.method === 'POST' && req.url === '/execute') { let body = ''; for await (const chunk of req) body += chunk; try { const payload = JSON.parse(body); const code = payload.code; const windowId = payload.windowId; // optional, uses active window if not specified if (!code || typeof code !== 'string') { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Missing "code" field (string)' })); return; } const result = await executeOnEda(code, windowId); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, result, windowId: windowId || activeEdaWindowId })); } catch (err) { const status = err.message?.includes('not connected') ? 503 : 500; res.writeHead(status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: err.message })); } return; } ``` ```javascript // lines 230-316 const wss = new WebSocketServer({ server: httpServer }); wss.on('connection', (ws, req) => { const clientType = req.url === '/eda' ? 'eda' : 'agent'; console.log(`[WS] New ${clientType} connection from ${req.socket.remoteAddress}`); // Send handshake message for client verification ws.send(JSON.stringify({ type: 'handshake', service: SERVICE_ID, clientType, timestamp: Date.now(), })); if (clientType === 'ed ...[truncated 6140 chars]- Remediation
View remediation
{ // startup handling }); ``` If IPv6 loopback support is required, create an explicitly controlled listener rather than accepting connections on unspecified interfaces. 2. **Require per-session authentication** - Generate a cryptographically random token at startup. - Require it in an `Authorization: Bearer ` header for every non-health HTTP endpoint. - Require the same token during the WebSocket upgrade, preferably through an authorization header or a short-lived challenge-response mechanism. - Do not place persistent secrets in source code, command-line arguments, or URLs. 3. **Authenticate EasyEDA clients separately** - Do not trust a client merely because it connects to `/eda`. - Pair the EasyEDA extension with the bridge using a one-time code or cryptographic session secret. - Reject duplicate or unrecognized window identifiers. - Bind pending responses to the authenticated EDA connection that received the request. 4. **Restrict browser access** - Replace `Access-Control-Allow-Origin: *` with a strict allowlist if browser-based callers are genuinely required. - Reject missing or unapproved `Origin` values on WebSocket upgrades. - If browser callers are unnecessary, omit CORS headers entirely. 5. **Reduce arbitrary execution capability** - Prefer a typed, allowlisted command protocol for required EDA operations. - Validate command names, argument types, project context, and target document type. - If arbitrary JavaScript must remain available, make it an explicit opt-in development mode with prominent warnings and stronger authentication. 6. **Apply request safeguards** - Enforce a small maximum HTTP request-body size and terminate oversized requests. - Limit WebSocket message size through the WebSocket server configuration. - Add rate limiting a ...[truncated 809 chars]
