// Vulnerability and fix
IDOR in Stripe checkout
What IDOR means in a checkout
IDOR (Insecure Direct Object Reference) is when swapping an identifier — in the URL, body, or a parameter — returns an object that is not yours. In checkout, that becomes access to another customer’s order, payment session, invoice, receipt, or subscription.
It is the number-one broken-access-control flaw precisely because it is easy to introduce: the code fetches by the received id and forgets to check that the current user owns that record.
Where it shows up with Stripe
The integration is safe; the hole is usually in your layer, between your session and the Stripe object.
- A route that fetches a Checkout Session or PaymentIntent by id without an owner check.
- A receipt/invoice endpoint that accepts any invoice id.
- A success page that trusts a session_id from the URL to grant access.
- A subscription portal that edits the subscription by a client-supplied id.
How to fix it
The fix is always the same: verify ownership on the server. Never assume that "knowing the id" proves the person may see the object. And do not use the URL session_id as proof of payment — confirm via the webhook or by querying Stripe server-side.
- Store the user↔object relationship and check it on every read/write.
- Prefer opaque, non-sequential ids, but do not rely on that alone (it is not access control).
- Grant paid access only after real confirmation (signed webhook), not the success page.
- Tenant scope on top of user scope.
When this needs manual proof
IDOR in a payment flow is exactly the finding that blocks a B2B sale and becomes bad news. When impact touches revenue and customer data, a scoped manual test (Manual Pentest) shows what breaks, with controlled evidence and fix priority.
Frequently asked questions
Does using UUIDs instead of sequential ids fix IDOR?
It reduces guessability, but it is not a fix. IDOR is a missing ownership check. If the route does not check who may see the object, a leaked id (in a log, referer, screenshot) still exposes the data.
Can the Stripe success page grant access?
Not as a source of truth. The session_id in the success URL does not prove payment. Confirm via the signed webhook or by querying Stripe server-side before unlocking a plan.
How do I know if my checkout has IDOR?
Create two accounts, place an order in each, and try to access one’s object using the other’s session (swapping ids). If data comes back, it is IDOR. On a revenue flow, validate it with a manual test.