Fix guide · critical · stripe_webhook_secret
Stripe webhook signing secret (whsec_) in client code
What this rule means
A string matching whsec_* was found in your deployed JavaScript.
Why it matters
The webhook signing secret is what proves an inbound webhook came from Stripe. With it, an attacker can forge webhook events — payment_intent.succeeded, customer.subscription.created, etc. — that your server happily accepts as legitimate.
How to fix it
- Roll the webhook secret. Stripe Dashboard → Developers → Webhooks → click your endpoint → "Roll signing secret".
- Update server-side env (
STRIPE_WEBHOOK_SECRET, no public prefix). - Verify every webhook with constructEvent before processing:
Next.js Route Handler:
// app/api/stripe/webhook/route.ts
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const sig = req.headers.get('stripe-signature')!;
const body = await req.text();
let event;
try {
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
} catch {
return new Response('Invalid signature', { status: 400 });
}
// safe to handle event
}
Express:
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
let event;
try {
event = stripe.webhooks.constructEvent(req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET);
} catch {
return res.status(400).send('Invalid signature');
}
// ...
});
Hono / Cloudflare Workers:
app.post('/webhook', async (c) => {
const sig = c.req.header('stripe-signature')!;
const body = await c.req.text();
const event = await stripe.webhooks.constructEventAsync(body, sig, c.env.STRIPE_WEBHOOK_SECRET);
// workers requires the async variant for Web Crypto
});
- Audit webhook deliveries in the Dashboard for events that didn't originate from your customers' real activity.
Did vibecheck flag this on your app?
If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.
Run another inspection