Significant-Gravitas/AutoGPT · error · HTTPException
Invalid webhook signature
Error message
Invalid webhook signature
What it means
The ingress endpoint calls webhook_manager.verify_signature(webhook, request) to check the provider's request-signature scheme (HMAC, RSA, etc.). Any non-HTTPException failure from verification — bad signature, missing signature header, malformed payload digest — is logged and converted to HTTP 403 'Invalid webhook signature'. A 403 (not 404) is deliberate: at this point the webhook's existence is already proven to the sender, so concealment adds nothing, and 403 correctly tells the sender its credentials for signing are wrong.
Solutions
- Replay the exact raw request body with the correct signature header computed over the untouched bytes (signature is computed on the raw body, not parsed JSON).
- If the secret rotated, re-register the webhook so a fresh secret is configured at the provider and stored server-side.
- Ensure any proxy in front of the backend passes the body through byte-identical and forwards the signature headers.
- Check backend logs: the logger.exception line 'Signature verification failed for webhook #{id}' includes the underlying exception with the precise reason.
Example fix
# before (unsigned test call)
curl -X POST https://api.example.com/integrations/github/webhooks/$ID/webhook -d '{"foo":1}'
# after (sign the raw body)
BODY=$(cat event.json)
SIG=$(python -c "import hmac,hashlib,sys;print(hmac.new(b'$SECRET',sys.stdin.buffer.read(),hashlib.sha256).hexdigest())" <<<"$BODY")
curl -X POST https://api.example.com/integrations/github/webhooks/$ID/webhook \
-H "X-Hub-Signature-256: sha256=$SIG" \
-H "Content-Type: application/json" \
-d "$BODY" Defensive patterns
Strategy: try-catch
Validate before calling
# Pre-flight: compute the signature the way the provider will import hmac, hashlib sig = "sha256=" + hmac.new(secret, raw_body_bytes, hashlib.sha256).hexdigest() assert sig == sent_header # self-check before relying on the receiver
Try / catch
# Only sane for test harnesses sending ingress traffic
resp = await client.post(ingress_url, content=raw, headers=sig_headers)
try:
resp.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.status_code == 403:
raise SignatureMisconfigured(ingress_url) from e # fix secret/transport, don't retry
raise Prevention
- Sign the exact raw bytes of the body; never re-serialize parsed JSON for signature computation.
- Keep proxies from rewriting the request body (disable modification/normalization).
- Re-register the webhook whenever its secret rotates so both sides agree.
When it happens
Trigger: Provider sends the event without the expected signature header (X-Hub-Signature-256 for GitHub, X-Signature-Ed25519 for Slack, X-Signature for Compass, etc.); the shared secret rotated and AutoGPT still verifies with the old one; a proxy/load balancer re-encodes or truncates the raw body so the digest doesn't match; manual curl testing without computing a signature.
Common situations: Testing ingress locally with plain curl; secret rotation on the provider side; reverse proxy (nginx/Cloudflare) modifying the body (e.g. chunked re-encoding) breaking HMAC; clock/lag between webhook registration and provider config propagation.
Related errors
- Invalid signature
- Webhook not configured
- AutoGPT-managed credentials cannot be deleted
- Cannot create credentials with a reserved ID
- {e}
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/cc6f6bf611da5439.
Report an issue: GitHub.
Appendix: source
Thrown at autogpt_platform/backend/backend/api/features/integrations/router.py:734
if webhook.credentials_id
else None
)
except NotFoundError as e:
logger.warning(f"Webhook payload received for unknown webhook #{webhook_id}")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
# Run provider signature verification (no-op for providers whose protocol
# has no signing scheme). 403 on failure; not 404 — that would leak
# webhook existence.
try:
await webhook_manager.verify_signature(webhook, request)
except HTTPException:
raise
except Exception:
logger.exception(
f"Signature verification failed for webhook #{webhook_id} ({provider.value})"
)
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid webhook signature",
)
payload, event_type = await webhook_manager.validate_payload(
webhook, request, credentials
)
logger.debug(
f"Validated {provider.value} {webhook.webhook_type} {event_type} event "
f"with payload {payload}"
)
webhook_event = WebhookEvent(
provider=provider,
webhook_id=webhook_id,
event_type=event_type,
payload=payload,
)View on GitHub (pinned to 9c8bb5550f)