{"record":{"id":"41135419ba95c0ba","repo":"unclecode/crawl4ai","slug":"webhook-header-not-allowed-name","errorCode":null,"errorMessage":"webhook header not allowed: {name}","messagePattern":"webhook header not allowed: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"deploy/docker/webhook.py","lineNumber":74,"sourceCode":"    \"content-type\", \"proxy-authorization\", \"authorization\", \"cookie\",\n    \"expect\", \"upgrade\", \"te\", \"trailer\",\n}\n_MAX_WEBHOOK_HEADERS = 20\n_MAX_WEBHOOK_HEADER_VALUE = 2048\n\n\ndef sanitize_webhook_headers(headers: Optional[Dict[str, str]]) -> Dict[str, str]:\n    \"\"\"Validate user-supplied webhook headers; raise ValueError on any bad one.\"\"\"\n    if not headers:\n        return {}\n    if len(headers) > _MAX_WEBHOOK_HEADERS:\n        raise ValueError(\"too many webhook headers\")\n    clean: Dict[str, str] = {}\n    for name, value in headers.items():\n        if not isinstance(name, str) or not _WEBHOOK_HEADER_NAME.match(name):\n            raise ValueError(f\"invalid webhook header name: {name!r}\")\n        if name.lower() in _WEBHOOK_DENY_HEADERS:\n            raise ValueError(f\"webhook header not allowed: {name}\")\n        sval = str(value)\n        if len(sval) > _MAX_WEBHOOK_HEADER_VALUE or any(c in sval for c in \"\\r\\n\\x00\"):\n            raise ValueError(f\"invalid value for webhook header {name}\")\n        clean[name] = sval\n    return clean\n\n\nclass WebhookDeliveryService:\n    \"\"\"Handles webhook delivery with exponential backoff retry logic.\"\"\"\n\n    def __init__(self, config: Dict):\n        \"\"\"\n        Initialize the webhook delivery service.\n\n        Args:\n            config: Application configuration dictionary containing webhook settings\n        \"\"\"\n        self.config = config.get(\"webhooks\", {})","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/deploy/docker/webhook.py#L56-L92","documentation":"ValueError from sanitize_webhook_headers when a header name (case-insensitive) is in _WEBHOOK_DENY_HEADERS - hop-by-hop and security-sensitive headers (content-length, host, connection, authorization, cookie, transfer-encoding, etc.) that users must not override on webhook deliveries.","triggerScenarios":"Including 'Content-Length', 'Host', 'Connection', 'Authorization', 'Cookie', 'Transfer-Encoding', 'Upgrade', 'Expect', 'TE', 'Trailer', or a proxy-authorization header in webhook.headers.","commonSituations":"Copying a full curl -H set or browser devtools request headers into the webhook config; trying to authenticate the webhook with an Authorization header not realizing it is deny-listed by the current server version.","solutions":["Remove the deny-listed header; let the server generate transport headers itself","If you need auth on the webhook, use a custom header name like X-Webhook-Token - check _WEBHOOK_DENY_HEADERS in deploy/docker/webhook.py for your version","Pass auth material as a query param or in the payload only if the receiver's threat model allows"],"exampleFix":"# before\n\"headers\": {\n  \"Host\": \"example.com\",\n  \"Authorization\": \"Bearer x\",\n  \"Content-Length\": \"123\"\n}\n\n# after\n\"headers\": {\n  \"X-Webhook-Token\": \"x\"\n}","handlingStrategy":"validation","validationCode":"DENY = {\"content-length\",\"host\",\"connection\",\"proxy-authorization\",\"authorization\",\"cookie\",\"expect\",\"upgrade\",\"te\",\"trailer\"}\nheaders = {k: v for k, v in headers.items() if k.lower() not in DENY}","typeGuard":"def has_no_denied_headers(h: dict) -> bool:\n    DENY = {\"content-length\",\"host\",\"connection\",\"proxy-authorization\",\"authorization\",\"cookie\",\"expect\",\"upgrade\",\"te\",\"trailer\"}\n    return not any(k.lower() in DENY for k in h)","tryCatchPattern":"try:\n    sanitize_webhook_headers(headers)\nexcept ValueError as e:\n    if \"not allowed\" in str(e):\n        bad = next(k for k in headers if k.lower() in DENY)\n        headers.pop(bad)\n        sanitize_webhook_headers(headers)","preventionTips":["Treat webhook headers as your app's custom headers only (X-*), never transport headers","Keep auth in a custom token header agreed with the receiver"],"tags":["crawl4ai","webhook","validation","http-headers","security"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}