Webhook handlers verify the signature
Why it matters
An unverified webhook endpoint is an open forged-event injection point: anyone who discovers the URL can POST a payment_intent.succeeded event with a fabricated payment amount and trigger fulfillment, subscription upgrades, or user privilege escalation without paying a cent. CWE-345 (Insufficient Verification of Data Authenticity) is the direct mapping. OWASP A07:2021 (Identification and Authentication Failures) applies: the server cannot distinguish a real Stripe event from a crafted one without signature verification. This is not a theoretical risk — Stripe explicitly documents the attack in their webhook security guide and provides constructEvent as the countermeasure.
Severity rationale
High because a forged webhook event can trigger financial side effects — fulfillment, subscription activation, refunds — with no authentication required beyond knowing the endpoint URL.
Remediation
Always verify the signature using the provider's SDK before reading the event body. For Stripe, use stripe.webhooks.constructEvent with the raw body string — not req.json(), which reparsing breaks the HMAC.
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
export async function POST(req: Request) {
const body = await req.text() // raw body required for HMAC
const sig = req.headers.get('stripe-signature')
if (!sig) return Response.json({ error: 'Missing signature' }, { status: 400 })
let event: Stripe.Event
try {
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!)
} catch {
return Response.json({ error: 'Invalid signature' }, { status: 400 })
}
// Safe to process — event is authentic
}
For Clerk or other providers using Svix, replace the Stripe call with new Webhook(secret).verify(body, headers) — the pattern is identical.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Hidden Cost Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-345 — Insufficient Verification of Data Authenticity
- owasp:2021 · A07
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-slop-cost-bombs·automated