T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/bridge-server.mjs:124
- Finding
- Unauthenticated Local Bridge Permits Arbitrary Code Execution in EasyEDA<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bridge-server.mjs:124-137, 198-219, 228-230, 272-287, 367-405, 459` **Vulnerability Type**: Unauthenticated arbitrary-code execution through a localhost HTTP/WebSocket bridge **Risk Level**: High The bridge intentionally accepts JavaScript and forwards it to a connected EasyEDA client, but it does not authenticate or authorize HTTP clients, WebSocket agents, or registering EDA clients. Although the server listens only on `127.0.0.1`, any local process can access it. A malicious web page may also target it because wildcard CORS is enabled and WebSocket origins are not validated. ### Vulnerable Code From `scripts/bridge-server.mjs:124-137`: ```javascript const httpServer = createServer(async (req, res) => { // CORS res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; } ``` From `scripts/bridge-server.mjs:198-219`: ```javascript // Execute code on EDA 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) { ``` From `scripts/bridge-server.mjs:228-230`: ```javascript // ─── WebSocket Server ────────────────────────── ...[truncated 5285 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Require strong authentication** - Generate a cryptographically random token when the bridge starts. - Require the token in an authorization header for every HTTP request. - Require an authenticated initialization message or token-bearing WebSocket subprotocol for every WebSocket connection. - Never place the token in URLs, logs, or health responses. 2. **Authenticate the EasyEDA gateway** - Pair the gateway with the bridge using a one-time server-issued nonce or user-approved secret. - Reject unauthenticated `register` messages. - Bind each registered window ID to the authenticated connection that created it. - Prevent duplicate or attacker-selected window IDs from silently replacing legitimate entries. 3. **Restrict browser access** - Remove `Access-Control-Allow-Origin: *`. - Disable CORS unless browser-based clients are explicitly required. - If browser access is necessary, use a strict origin allowlist and reject `null` or unrecognized origins. - Validate the `Origin` header during WebSocket upgrades. 4. **Replace unrestricted code execution** - Prefer a structured RPC protocol with an allowlist of supported EasyEDA operations. - Validate operation names, parameter types, document targets, and permitted data sizes. - Separate read-only operations from mutating or destructive operations. - If arbitrary code remains necessary for debugging, make it an explicit temporary mode that is disabled by default. 5. **Require user confirmation** - Display the requested operation and target EasyEDA window before executing arbitrary, mutating, file-related, or destructive actions. - Use short-lived approvals rather than granting permanent access for the entire bridge lifetime. 6. **Harden request processing** - Set maximum HTTP body and WebSocket message sizes. - Add rate limiting and connection limits. - Apply strict JSON schema validation. - Reject missing, malf ...[truncated 737 chars]
