T07 · Tool Hijacking and Spoofing
Error
- Location
- extension/index.ts:83
- Finding
- Unauthenticated Legacy HTTP Control Plane Enables Godot Session Spoofing and Command Interception<![CDATA[ ## Vulnerability Details **File Location**: `extension/index.ts:83-85`, `extension/index.ts:104-106`, `extension/index.ts:114-139`, `extension/index.ts:161-204`, `extension/index.ts:207-224`, `extension/index.ts:255-263`, and `extension/index.ts:310-314` **Vulnerability Type**: Missing authentication and unrestricted cross-origin access on security-sensitive HTTP endpoints **Risk Level**: High ### Vulnerable Code ```ts function sendJson(res: ServerResponse, status: number, data: any) { res.statusCode = status; res.setHeader("Content-Type", "application/json"); res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); res.end(JSON.stringify(data)); } ``` ```ts // Handle CORS preflight if (req.method === "OPTIONS") { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); res.statusCode = 204; res.end(); return true; } ``` ```ts case "register": { if (req.method !== "POST") { sendJson(res, 405, { error: "Method not allowed" }); return true; } const body = await readJsonBody(req); const { project, version, platform, tools } = body; const sessionId = generateId(); const session: GodotSession = { sessionId, registeredAt: Date.now(), lastHeartbeat: Date.now(), projectName: project || "Unknown", godotVersion: version || "Unknown", platform: platform || "GodotEditor", toolCount: tools || 0, pendingCommands: [], results: new Map(), }; sessions.set(sessionId, session); console.log(`[Godot] Registered: ${project} (${version}) - Session: ${sessionId}`); sendJson(res, 200, { sessionId, status: "connected" }); return true; } ``` ```ts case "poll": { const sessionId = url.searchParams.get("s ...[truncated 5810 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove the unauthenticated compatibility path** - Require `registerHttpRoute` with `auth: "plugin"`. - If legacy versions must remain supported, implement explicit authentication inside `handleGodotHttpRequest` before dispatching any endpoint. - Fail closed when the gateway cannot provide an authenticated route. 2. **Use per-session authentication** - Generate a cryptographically random session secret with `crypto.randomBytes()` or `crypto.randomUUID()`. - Require the secret for heartbeat, polling, and result submission. - Compare credentials using a timing-safe comparison where appropriate. - Rotate or invalidate credentials when sessions expire. 3. **Protect session identifiers and metadata** - Do not expose raw session IDs through an unauthenticated status endpoint. - Restrict status information to authorized administrative callers. - Return only the minimum metadata required for operation. 4. **Restrict CORS** - Replace `Access-Control-Allow-Origin: *` with an explicit allowlist of trusted local origins. - Do not enable cross-origin credentialed control-plane requests unless strictly necessary. - Reject untrusted `Origin` headers rather than merely omitting browser response headers. 5. **Reduce network exposure** - Bind the gateway endpoint to loopback by default. - Require authenticated TLS when remote access is necessary. - Document firewall requirements and prevent public-network exposure by default. 6. **Bind results to issued commands** - Record the expected session and command identifier when a command is queued. - Accept each result only from the authenticated session to which the command was assigned. - Reject unknown, duplicate, expired, or already-completed `toolCallId` values. - Add expiration and size limits for pending commands and stored results. 7. **Avoid implicit first-session selection** - Require explicit user selection when multiple ...[truncated 521 chars]
