Significant-Gravitas/AutoGPT · critical · HTTPException

Webhook not configured

Error message

Webhook not configured

What it means

Raised (503) by POST /credits/stripe_webhook when settings.secrets.stripe_webhook_secret is empty. The comment makes the security rationale explicit: with an empty secret, an attacker could compute a valid HMAC signature over the same empty key and forge webhook events (e.g. fake payment completions). All webhook deliveries are therefore rejected until the secret is configured.

Source

Thrown at autogpt_platform/backend/backend/api/features/v1.py:1426

            "stripe_webhook: dedup release failed for event %s",
            event_id,
            exc_info=True,
        )


@v1_router.post(
    path="/credits/stripe_webhook", summary="Handle Stripe webhooks", tags=["credits"]
)
async def stripe_webhook(request: Request):
    webhook_secret = settings.secrets.stripe_webhook_secret
    if not webhook_secret:
        # Guard: an empty secret allows HMAC forgery (attacker can compute a valid
        # signature over the same empty key). Reject all webhook calls when unconfigured.
        logger.error(
            "stripe_webhook: STRIPE_WEBHOOK_SECRET is not configured — "
            "rejecting request to prevent signature bypass"
        )
        raise HTTPException(status_code=503, detail="Webhook not configured")

    # Get the raw request body
    payload = await request.body()
    # Get the signature header
    sig_header = request.headers.get("stripe-signature")

    try:
        event = stripe.Webhook.construct_event(payload, sig_header, webhook_secret)
    except ValueError:
        # Invalid payload
        raise HTTPException(status_code=400, detail="Invalid payload")
    except stripe.SignatureVerificationError:
        # Invalid signature
        raise HTTPException(status_code=400, detail="Invalid signature")

    # Defensive payload extraction. A malformed payload (missing/non-dict
    # `data.object`, missing `id`) would otherwise raise KeyError/TypeError
    # AFTER signature verification — which Stripe interprets as a delivery

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Set STRIPE_WEBHOOK_SECRET to the signing secret of the webhook endpoint (Stripe Dashboard > Developers > Webhooks, or `stripe listen` output for local dev) and restart the backend.
  2. If the endpoint was recreated in Stripe, copy the NEW whsec_... value — secrets change per endpoint.
  3. Confirm the secret actually reaches the process (container env, secret mount) rather than only existing in CI.

Example fix

# before
# STRIPE_WEBHOOK_SECRET=  (empty)

# after
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxx
Defensive patterns

Strategy: validation

Validate before calling

# pre-deploy check
import os
assert os.environ.get('STRIPE_WEBHOOK_SECRET', '').startswith('whsec_'), \
    'STRIPE_WEBHOOK_SECRET missing — webhook endpoint will 503'

Try / catch

Stripe webhook 503 is server-side misconfiguration; callers (Stripe) will retry automatically — monitor delivery failures in the Stripe dashboard rather than catching client-side.

Prevention

When it happens

Trigger: Stripe sends a webhook to an environment where STRIPE_WEBHOOK_SECRET is unset/empty — fresh deployments, local dev without the Stripe CLI secret, or a secrets migration that dropped the variable.

Common situations: New environment not registered in the Stripe dashboard; developer testing webhooks locally but forgetting to copy the `whsec_...` from `stripe listen`; Helm/K8s secret not mounted; rotated webhook endpoint in Stripe dashboard generating a new secret never propagated to the app.

Related errors


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