unclecode/crawl4ai · warning · ValueError
webhook header not allowed: {name}
Error message
webhook header not allowed: {name} What it means
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.
Source
Thrown at deploy/docker/webhook.py:74
"content-type", "proxy-authorization", "authorization", "cookie",
"expect", "upgrade", "te", "trailer",
}
_MAX_WEBHOOK_HEADERS = 20
_MAX_WEBHOOK_HEADER_VALUE = 2048
def sanitize_webhook_headers(headers: Optional[Dict[str, str]]) -> Dict[str, str]:
"""Validate user-supplied webhook headers; raise ValueError on any bad one."""
if not headers:
return {}
if len(headers) > _MAX_WEBHOOK_HEADERS:
raise ValueError("too many webhook headers")
clean: Dict[str, str] = {}
for name, value in headers.items():
if not isinstance(name, str) or not _WEBHOOK_HEADER_NAME.match(name):
raise ValueError(f"invalid webhook header name: {name!r}")
if name.lower() in _WEBHOOK_DENY_HEADERS:
raise ValueError(f"webhook header not allowed: {name}")
sval = str(value)
if len(sval) > _MAX_WEBHOOK_HEADER_VALUE or any(c in sval for c in "\r\n\x00"):
raise ValueError(f"invalid value for webhook header {name}")
clean[name] = sval
return clean
class WebhookDeliveryService:
"""Handles webhook delivery with exponential backoff retry logic."""
def __init__(self, config: Dict):
"""
Initialize the webhook delivery service.
Args:
config: Application configuration dictionary containing webhook settings
"""
self.config = config.get("webhooks", {})View on GitHub (pinned to 7e80152142)
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
Example fix
# before
"headers": {
"Host": "example.com",
"Authorization": "Bearer x",
"Content-Length": "123"
}
# after
"headers": {
"X-Webhook-Token": "x"
} Defensive patterns
Strategy: validation
Validate before calling
DENY = {"content-length","host","connection","proxy-authorization","authorization","cookie","expect","upgrade","te","trailer"}
headers = {k: v for k, v in headers.items() if k.lower() not in DENY} Type guard
def has_no_denied_headers(h: dict) -> bool:
DENY = {"content-length","host","connection","proxy-authorization","authorization","cookie","expect","upgrade","te","trailer"}
return not any(k.lower() in DENY for k in h) Try / catch
try:
sanitize_webhook_headers(headers)
except ValueError as e:
if "not allowed" in str(e):
bad = next(k for k in headers if k.lower() in DENY)
headers.pop(bad)
sanitize_webhook_headers(headers) Prevention
- 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
When it happens
Trigger: Including 'Content-Length', 'Host', 'Connection', 'Authorization', 'Cookie', 'Transfer-Encoding', 'Upgrade', 'Expect', 'TE', 'Trailer', or a proxy-authorization header in webhook.headers.
Common situations: 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.
Related errors
- invalid webhook header name: {name!r}
- invalid header name {name!r}
- URL must have a valid hostname
- URL blocked
- too many webhook headers
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/41135419ba95c0ba.
Report an issue: GitHub.