T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/track17.py:1237
- Finding
- Webhook Signature Validation Fails Open<![CDATA[ ## Vulnerability Details **File Location**: `scripts/track17.py:1237-1309` **Vulnerability Type**: Authentication bypass and untrusted webhook ingestion **Risk Level**: High ### Vulnerable Code ```python sig_valid: Optional[bool] = None if secret and sig_value: expected = compute_webhook_signature(raw_body, secret) sig_valid = expected.lower() == sig_value.lower() payload_sha = store_payload( conn, raw_body=raw_body, source=source, event_type=None, number=None, carrier=None, signature=sig_value, signature_valid=sig_valid, ) payload = parse_webhook_payload(raw_body) ``` The payload is subsequently applied regardless of the signature result: ```python # Ensure package exists pkg = conn.execute( "SELECT * FROM packages WHERE number=? AND carrier=? AND param=? ORDER BY id DESC LIMIT 1", (number_s, carrier_i, param), ).fetchone() if not pkg: pkg = upsert_package( conn, number=number_s, carrier=carrier_i, param=param, label=None, tag=tag, lang=os.environ.get("TRACK17_LANG") or "en", api_registered=True, ) # Use the data object as the response item; it includes track_info. changed, summary = apply_update_from_trackinfo( conn, package_row=pkg, response_item=data, raw_payload_sha=payload_sha, source=source, ) if secret and sig_value: validity = "valid" if sig_valid else "INVALID" summary = f"[{validity} signature via {sig_header_name}] " + summary elif secret and not sig_value: summary = "[no signature header] " + summary ``` ### Technical Analysis When `TRACK17_WEBHOOK_SECRET` is configured, the code calculates whether the supplied signature is valid, but does not use that result as an authorization decision. An invalid signature is only recorded in the database and displayed in a summary. A missing signature is similarly noted without causing rejection. As a result, signature validation operates ...[truncated 1804 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. When a webhook secret is configured, reject the payload before storage or parsing if the signature is missing or invalid. 2. Use constant-time comparison: ```python import hmac if secret: if not sig_value: raise Track17Error("Missing webhook signature") expected = compute_webhook_signature(raw_body, secret) if not hmac.compare_digest(expected.lower(), sig_value.lower()): raise Track17Error("Invalid webhook signature") ``` 3. Perform authentication before calling `store_payload`, `parse_webhook_payload`, `upsert_package`, or `apply_update_from_trackinfo`. 4. Return an HTTP 401 or 403 response for unauthenticated network webhook requests rather than acknowledging them with HTTP 200. 5. Consider requiring a webhook secret whenever the server binds to a non-loopback interface. 6. Add tests confirming that missing, malformed, and incorrect signatures cannot create or modify database records. 7. Store rejected-request metadata only if operationally necessary, and do not retain the full untrusted body by default. ]]>
