T07 · Tool Hijacking and Spoofing
- Location
extension/index.ts:280- Finding
Legacy HTTP Registration Fallback Lacks an Explicit Authentication Boundary
- Content
View full analysis
Vulnerability Details
File Location:
extension/index.ts:280-307, 318-426, 454-465
Vulnerability Type: Unauthenticated tool bridge and session spoofing
Risk Level: HighVulnerable 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 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: UnrealSession = { sessionId, registeredAt: Date.now(), lastHeartbeat: Date.now(), projectName: project || "Unknown", engineVersion: version || "Unknown", platform: platform || "UnrealEditor", toolCount: tools || 0, pendingCommands: [], results: new Map(), }; sessions.set(sessionId, session); console.log(`[Unreal] Registered: ${project} (UE ${version}) - Session: ${sessionId}`); sendJson(res, 200, { sessionId, status: "connected" }); return true; }ts case "poll": { const sessionId = url.searchParams.get("sessionId"); const session = sessions.get(sessionId || ""); if (!session) { sendJson(res, 404, { error: "Session not found" }); return true; } session.lastHeartbeat = Date.now(); if (session.pendingCommands.length > 0) ...[truncated 4075 chars]- Remediation
View remediation
Remediation Suggestions
- Remove the unauthenticated legacy fallback or require a minimum OpenClaw version that supports authenticated route registration.
- If legacy compatibility is required, implement authentication inside
handleUnrealHttpRequestso security does not depend on the registration API:- Require a cryptographically strong shared secret or verified gateway identity.
- Use constant-time secret comparison.
- Reject every unauthenticated request before endpoint dispatch.
- Bind each session to its authenticated principal and verify ownership on
heartbeat,poll, andresult. - Do not disclose session IDs through a broadly accessible status endpoint. Return only non-sensitive aggregate status unless the requester is authorized.
- Replace wildcard CORS with an explicit trusted-origin allowlist, or disable CORS because the Editor bridge does not require arbitrary browser access.
- Use cryptographically secure session identifiers, such as
crypto.randomUUID()or random bytes fromnode:crypto, instead ofDate.now()combined withMath.random(). - Prevent session-registration races and default-session spoofing:
- Require an authenticated Editor identity.
- Select sessions explicitly rather than using the first map entry.
- Consider requiring pairing or administrator approval for new Editors.
- Add integration tests covering both registration APIs and verifying that:
- Unauthenticated registration is rejected.
- Session IDs cannot be enumerated anonymously.
- One authenticated session cannot poll or submit results for another.
- Browser-originated requests from untrusted origins are rejected.
- Spoofed sessions cannot become the implicit destination of Agent commands.
