T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:410
- Finding
- Unauthenticated Webhook Events Can Trigger Agent Processing and Negotiation Actions<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:410-428` **Vulnerability Type**: Missing webhook authentication and replay protection **Risk Level**: High ### Vulnerable Code ```python @app.post("/yoap/request") async def handle_yoap(request: Request): data = await request.json() event_type = data["type"] if event_type == "message": # Direct message received await process_dm(data) elif event_type == "thread_created": # Someone started a negotiation with us await auto_review_proposal(data["threadId"], data["proposal"]) elif event_type == "thread_reply": # Counterparty replied in a thread await handle_negotiation(data["threadId"], data["replyType"]) elif event_type == "channel_message": # Group message in a channel await process_channel_msg(data["channelId"], data["content"]) return {"status": "received"} ``` ### Technical Analysis The documented webhook handler trusts every JSON request received at `/yoap/request`. It does not verify a cryptographic signature, shared secret, authenticated client identity, timestamp, nonce, source address, or replay identifier. Attacker-controlled fields are passed directly to message and negotiation handlers. In particular, a forged `thread_created` event can invoke `auto_review_proposal`, while forged direct or channel messages can reach downstream agent-processing logic. Input schema validation alone would not solve the issue because an attacker can submit syntactically valid events. The handler must establish that events originated from the expected YOAP relay and are fresh. ### Attack Path 1. An agent registers an Internet-accessible webhook endpoint following the Skill's example. 2. An attacker discovers or guesses the endpoint, or obtains it from configuration, logs, or registration data. 3. The attacker sends a forged request such as: ```http POST /yoap/request Content-Type: application/json { "type": " ...[truncated 1213 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require every webhook request to carry a cryptographic signature generated with a per-registration secret. 2. Verify the signature over the exact raw request body before parsing or processing the JSON. 3. Include a signed timestamp and unique event identifier, enforce a narrow clock-skew window, and store processed identifiers to prevent replay. 4. Use constant-time signature comparison and reject requests with missing, malformed, or invalid authentication headers. 5. Validate each event against a strict schema, including allowed event types, identifier formats, field lengths, and nested object limits. 6. Apply request-size limits, rate limiting, and processing timeouts. 7. Require explicit human approval before accepting proposals, confirming negotiations, disclosing contact information, or performing other consequential actions. 8. Bind events to the registered agent and verify that referenced threads or channels belong to that agent. 9. Log rejected authentication attempts without recording secrets or sensitive message content. 10. Where supported, add transport-level controls such as mutual TLS or relay IP allowlisting as defense in depth, not as a replacement for signed events. ]]>
