security
May 5, 2026
By Teun
6,000 web apps scanned, 1,542 accepted forged Stripe events
A security scan of about 6,000 web apps found 1,542 webhook endpoints that accepted forged Stripe-style events without a Stripe-Signature header. The findings affect custom-domain SaaS apps and hosted preview deployments across services including Render, Vercel, Replit, and Railway.
A scan of roughly 6,000 web apps found 1,542 webhook endpoints that accepted forged Stripe-style payment events without checking a Stripe-Signature header, according to the researchers who ran the test. The scan targeted common payment-webhook paths and sent a minimal fake checkout.session.completed event to see whether servers would process it.
The module was intentionally simple. It POSTed a Stripe-shaped JSON body to webhook URLs such as /api/webhook/stripe, /webhooks/stripe, and similar variants used for Stripe, Paddle, and LemonSqueezy. If a server returned a 200, 201, or 202 response, the researchers counted it as accepting the unsigned event.
According to the writeup, 1,542 apps did accept the request. That is about one in four of the hosts they scanned that exposed a payment-webhook-shaped URL. The researchers said the result means those servers had no auth, no signature verification, and no replay protection for the webhook message.
A real Stripe webhook includes a Stripe-Signature header generated with a webhook secret. The researchers said that header is the only cryptographic proof that the event came from Stripe. Without it, any HTTP client that can reach the endpoint can send an event that looks valid enough to the application.
The practical risk is straightforward. Many SaaS apps use webhooks to move a user from a free plan to a paid plan after checkout. If the application trusts the event body without verifying the signature first, an attacker can send a fake checkout.session.completed message and trigger the same account-upgrade logic.
The researchers said the weakest pattern is an app that looks up the customer from a field inside the event body, such as an email address or session ID. In that case, they said, an attacker may only need the webhook URL and a guessed or self-chosen identifier in the payload.
The hits were spread across several environments. Roughly half were on custom domains, which the researchers described as production SaaS apps, and half were on hosted preview platforms. They listed Render with 198 hits, Vercel with 142, Replit with 121, Railway with 87, Fly.dev with 64, Heroku with 58, and about 150 more across Lovable, Bolt, Netlify, and others.
One anonymized example the researchers described was a hotel booking site on Render. Its /api/webhook/paddle endpoint returned 200 OK to a forged event, which suggested the app accepted and likely acted on the message. The researchers said they did not follow through with a real exploit, but disclosed the issue privately to the operator, who acknowledged it within four hours.
The article also described why this mistake persists. Developers often build the handler locally with a stub that logs the event, then ship the upgrade logic first and leave signature verification for later. The researchers said that same pattern appears in apps generated by code assistants, where the route accepts JSON and calls the business logic, but signature verification is left for the developer to remember.
The fix, according to the article, is to verify the signature before doing anything else with the payload. In Stripe’s Node example, that means reading the Stripe-Signature header, using the raw request body rather than parsed JSON, and passing both to Stripe’s webhook verification helper with the endpoint secret from the Stripe dashboard.
The researchers said Express users often need express.raw({type: 'application/json'}) on the webhook route because default JSON parsing changes the body before signature verification runs. They said FastAPI users should read await request.body() directly, and that Paddle, LemonSqueezy, and other payment processors have equivalent verification steps in their SDKs.
The researchers also said their 1,542 figure only covers endpoints that returned a 2xx response to unsigned events. They noted that a 200 response does not prove the app actually granted access or upgraded an account, since some systems log webhooks or queue them for later validation. Even so, they said the response shows the endpoint accepted an unsigned payment event, which is a security problem on its own.
The researchers said they offer the scan as part of their security scanner and provide a quick test that checks the common webhook path variants. They said the issue is fixable with the official webhook verification code from Stripe or the relevant payment provider.