T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/webhook_server.py:64
- Finding
- Unauthenticated and Unbounded Network Webhook Receiver<![CDATA[ ## Vulnerability Details **File Location**: `scripts/webhook_server.py`, lines 64-71 and 109-110 **Vulnerability Type**: Unauthenticated network service with unbounded request processing **Risk Level**: High ### Vulnerable Code ```python def do_POST(self): """Handle POST request from Jellyseerr.""" content_length = int(self.headers.get('Content-Length', 0)) body = self.rfile.read(content_length) try: data = json.loads(body) logger.info(f"Received webhook: {json.dumps(data, indent=2)}") ``` ```python def run_server(port=8384): """Run the webhook server.""" server = HTTPServer(('0.0.0.0', port), WebhookHandler) ``` ### Technical Analysis The webhook server binds to `0.0.0.0`, making it reachable through every available network interface. It does not authenticate webhook requests, verify a shared secret, validate the source address, or check a cryptographic signature. The supplied `Content-Length` is converted to an integer and used directly as the number of bytes to read. There is no maximum body size and no socket timeout. A client can therefore advertise a very large request or send the body extremely slowly, consuming memory or blocking the single-threaded `HTTPServer`. Attacker-controlled webhook content is also written in full to the systemd journal. For a `MEDIA_AVAILABLE` request, the attacker-controlled `subject` is placed into the notification queue and subsequently emitted by `scripts/send_notifications.py` as a `SEND_MESSAGE:` record. This permits forged availability notifications and can expose or propagate untrusted content into downstream notification processing. The queue file is repeatedly loaded, appended to, and rewritten without a queue-size limit. Repeated forged requests can consequently cause persistent cache and journal growth. ### Attack Path 1. The operator installs and starts the webhook service on TCP port 8384. 2. The service listens on all interfaces, and the port becomes ...[truncated 1316 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Require a high-entropy webhook secret, preferably through an HMAC signature header verified with constant-time comparison. - Alternatively, place the receiver behind an authenticated reverse proxy and restrict direct access to the application port. - Bind to a specific trusted interface or `127.0.0.1` when remote network access is unnecessary. - Reject missing, negative, malformed, or excessive `Content-Length` values before reading the body. - Enforce a small request-body limit appropriate for Jellyseerr notifications, such as 16–64 KiB. - Configure socket read timeouts and reverse-proxy request timeouts. - Apply source-network firewall restrictions so only the Jellyseerr host can connect. - Validate the JSON object against a strict schema, including field types and maximum string lengths. - Rate-limit requests and cap the number and total size of queued notifications. - Avoid logging complete untrusted request bodies; log only validated event metadata. - Use atomic file replacement and restrictive permissions for the notification queue. - Consider `ThreadingHTTPServer` or a production webhook framework, while still enforcing concurrency and resource limits. ]]>
