Payments Preflight · Check 1 of 15

Verify every webhook signature

Check that your Stripe webhook endpoint verifies the Stripe-Signature header with the raw body and your whsec_ secret before acting on any event.

What it is

Stripe signs each webhook event it sends. The Stripe-Signature header lets your server confirm the event came from Stripe and was not changed.

Why it matters

Your webhook URL is public. If it does not verify signatures, anyone can POST a fake checkout.session.completed and unlock paid features.

How to check

How to fix it

  1. Copy the endpoint signing secret (whsec_) from the Dashboard, or from stripe listen for local work.
  2. Read the raw body, call stripe.webhooks.constructEvent(body, sig, secret), return 400 if it throws.
  3. Keep the library's default timestamp tolerance (5 minutes) to limit replayed events.
// app/api/stripe/webhook/route.ts
const body = await req.text(); // raw body
const sig = req.headers.get("stripe-signature")!;
let event: Stripe.Event;
try {
  event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
} catch {
  return new Response("Bad signature", { status: 400 });
}

Prompt for your AI coding tool

Paste into Cursor, Claude Code, Lovable or similar. Review the diff before you accept it.

Review my Stripe webhook handler. Make sure it reads the raw request body, verifies the Stripe-Signature header with stripe.webhooks.constructEvent and the STRIPE_WEBHOOK_SECRET env var, and returns 400 before doing anything else if verification fails. Do not parse the body as JSON before verifying. Show me the diff.

Sources

Related checks

All payments checks

Sponsor this page: get in touch.

Get new checks by email

New checks and real leak post-mortems, about once a month. No spam.