T05 · Unauthorized Access and Privilege Escalation
- Location
examples/advanced-agent.ts:522- Finding
Unauthenticated Webhook Can Trigger Authenticated Gameplay Actions
- Content
View full analysis
{ body += chunk.toString(); }); req.on("end", async () => { try { const event: WebhookEvent = JSON.parse(body); await this.handleWebhook(event); ``` The accepted event is subsequently passed to an action-capable handler: ```typescript case "turn_start": if (event.gameId === this.currentGameId) { this.log(`Turn ${event.turnNumber} started (phase: ${event.phase})`); await this.playTurn(event.gameId); } break; ``` ### Technical Analysis The public webhook accepts JSON without verifying an HMAC signature, access token, trusted source, timestamp, nonce, event schema, or game ownership. The TypeScript type annotation does not provide runtime validation. The request body also has no size limit. An attacker who can reach the listener can submit arbitrarily large bodies or forged game events. A valid-looking `turn_start` event for the current game reaches `playTurn()`, which uses the agent's bearer credential to perform game actions. Although receiving webhooks is necessary for the Skill's declared real-time gameplay functionality, accepting unauthenticated action-triggering messages exceeds the minimum privileges required. ### Attack Path 1. The user exposes port 3000 through a public tunnel or cloud deployment, as directed by the example documentation. 2. An attacker identifies the `/webhook` endpoint. 3. The attacker submits a forged `game_start` event to set `currentGameId`, or obtains a game ID from logs or other exposed metadata. 4. The attacker submits a forged `turn_start` event for that game. 5. `handleWebhook()` accepts the event and invokes `playTurn()`. 6. The agent performs authenticated summo ...[truncated 484 chars]- Remediation
View remediation
