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.

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)

Solutions

  1. 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).
  2. If the secret rotated, re-register the webhook so a fresh secret is configured at the provider and stored server-side.
  3. Ensure any proxy in front of the backend passes the body through byte-identical and forwards the signature headers.
  4. 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

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


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/cc6f6bf611da5439. Report an issue: GitHub.