Stripe webhook security

The answer is while you technically cannot access the raw body, you can get around this by reconstructing the body to what it should look like as per the docs. I agree they shouldn’t modify it and fix the issue, but this the workaround. If you need to secure your webhooks today this is the only way.


Thanks, I think we all read the Stripe docs here :slight_smile:
It’s extremely easy to check the signature with node crypto, and the stripe library makes it even easier. I am sure that anybody that doesn’t know how to make a plugin in bubble can benefit from your plugin, but the problem here is that the input data is not readily available in bubble.

That’s the point, the formatting of a json payload is not a change to validation protocols, so it can change at any time.
I guess it’s up to the developer to decide if that’s a risk for the app or not.
The alternative is to treat the webhook as not secure and don’t trust the data. Use it just as a trigger to securely require the data from the stripe API.

1 Like

Yes I agree… and I understand what you’re saying now…

But the problem here is that Stripe seem to use irregular, and inconsistent formatting in the request bodies (specifically, as @dorilama has pointed out, with regard to empty objects and empty arrays), which makes trying to reconstruct what the request body should look like difficult and prone to errors…

Plus they do change their API now and again, and the request body format has changed several times over the past few years.


Yeah, it is 100% a problem. When that change occurs, you’d have to change the format you created. This is a shitty situation, but at least you can protect yourself from bad actors. My app operates in the US political space, and there are a lot of those so I don’t care if in 2 years from now our webhooks won’t work for a day or two until I fix the problem

1 Like

What I’ve done for this was simply put a condition on the workflow.

Hey! Does that do the job? Is it enough to fix the vulnerability?

Essentially yes, because stripe would have you implement a time dilation method as well. Someone can correct me if I’m wrong but this workflow will only execute once when the posted data matches the criteria. And I think 10 seconds is just fine. But one could do up to 5 mins and maybe less than 10 seconds. 10 seconds from event works for me.

the point is that request data can’t be trusted until it’s verified so… :man_shrugging:

Not really. But it’s one of the easier ways to implement at least something…
I’d recommend rechecking the Event ID that Stripe is sending.

Receive webhook → extract Event ID → Request the event again from Stripe → If the event is not in their system then don’t proceed

1 Like

Maybe a workaround that could also work because I don’t use stripe. Why not use zapier or a cheaper alternative for it? (I use

I don’t know if stripe works exactly like this but the workflow could look like this:
Stripe IPN → Zapier (or alternative) → Bubble Create a new Thing in Database.

You set up the URL in Zapier from which webhook/ipn you reveivce data. So it is more secure.
The cool thing using a third party handler is you could also directly put the user into your email marketing system, crm etc.

This is something, as a creator, I was banging my head against a few weeks ago while making a video on webhooks. Exactly as @adamhholmes has said it’s the raw response body that is the issue.

The most accessible solution to my mind, which I’ve recorded a tutorial on (to be released later this week), is to setup Hookdeck to receive the webhooks from Stripe, and then have Hookdeck relay those to your Bubble app.

Hookdeck has support for validating Stripe webhooks out of the box and you can insert your Bubble app’s API token as a header in the Hookdeck > Bubble request as the method of validating the Hookdeck requests.

I’ll share the tutorial here when it’s posted.

Shout out to @jamesdevonport for putting me on to this solution.

1 Like

Thank you for paying attention to this in your tutorial.
I have found way too many tutorials that skip this crucial step entirely.

Here’s the tutorial with the approach I mentioned above. Any feedback appreciated!


This topic was automatically closed after 70 days. New replies are no longer allowed.