T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/webhook_server.py:38
- Finding
- Publicly Exposed Webhook Receiver Lacks Authentication and Request-Size Limits## Vulnerability Details **File Location**: `scripts/webhook_server.py`, lines 38–59 and line 174 **Vulnerability Type**: Unauthenticated webhook processing and unbounded request-body handling **Risk Level**: Medium ### Vulnerable Code ```python def do_POST(self): """Handle webhook POST requests.""" if self.path == "/webhook/manus": content_length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(content_length) try: data = json.loads(body.decode("utf-8")) self.handle_manus_webhook(data) self.send_response(200) self.send_header("Content-Type", "application/json") self.end_headers() self.wfile.write(b'{"status": "ok"}') except Exception as e: print(f"❌ Error processing webhook: {e}") self.send_response(400) self.end_headers() else: self.send_response(404) self.end_headers() ``` ```python server = HTTPServer(("0.0.0.0", args.port), WebhookHandler) ``` ### Technical Analysis The HTTP server binds to `0.0.0.0`, making it reachable through every available network interface unless external firewall rules prevent access. The webhook endpoint accepts JSON events without verifying a cryptographic webhook signature, shared secret, timestamp, source identity, or other proof that the request originated from Manus. The handler also converts the attacker-controlled `Content-Length` header to an integer and passes it directly to `self.rfile.read()` without enforcing a maximum request size. This permits excessive memory consumption and allows clients to hold the single-threaded server while slowly transmitting a declared request body. Attacker-controlled event fields—including task identifiers, titles, and error messages—are printed to the terminal without sanitizing control characters ...[truncated 1514 chars]
- Remediation
- ## Remediation Suggestions 1. Bind to `127.0.0.1` by default. Require an explicit command-line option to listen on public or non-loopback interfaces. 2. Verify the webhook provider's cryptographic signature over the raw request body. Reject requests with missing, malformed, stale, or invalid signatures, and use constant-time comparison where applicable. 3. Add replay protection by validating a signed timestamp and rejecting events outside a short permitted time window. Track event identifiers if the provider supports them. 4. Enforce a small maximum request-body size before calling `read()`. Return HTTP `413 Payload Too Large` when the declared size exceeds the limit. 5. Configure connection and read timeouts. Consider a hardened, concurrent production HTTP server when public exposure is required. 6. Require an appropriate JSON `Content-Type` and validate the event payload against a strict schema before processing it. 7. Sanitize carriage returns, newlines, escape sequences, and other terminal-control characters before printing remote fields. 8. Place any externally reachable deployment behind a TLS-enabled reverse proxy with firewall rules, rate limiting, and request-size limits.
