Posted on 17/07/2026 16:11:21
1) Is CheckoutHandlerOrderID the only identifier?
Yes — CheckoutHandler.RedirectToCheckoutHandler() resolves the order purely from CheckoutHandlerOrderID/s_CheckoutHandlerOrderID, with no secondary secret check on the way in. But this only matters for confidentiality, not integrity: an attacker can cause Redirect() to be invoked for someone else's order, but each checkout handler's Redirect() implementation independently validates the payment with the gateway (transaction ID, signature/hash from the gateway, gateway's own reference for that order) before calling SetOrderComplete. So guessing/incrementing CheckoutHandlerOrderID alone can't complete or tamper with another customer's order — the gateway-side validation is the actual security boundary, not the order id.
But you're right that it's guessable/enumerable, so it shouldn't be trusted as an authorization token — and it isn't used as one for the completion step. It's only used as a lookup key, which is fine.
2) Receipt page manipulation
The receipt page is not actually unauthenticated by order id alone:
- The receipt/completed-order flow requires both CompletedOrderId and CompletedOrderSecret in the query string.
- CompletedOrderSecret is checked against order.Secret which is a Guid.NewGuid().ToString("N") generated server-side - a 128-bit random value, not derived from the order id and not guessable/enumerable.
- If the secret doesn't match, GetOrder() returns null and the receipt isn't shown.
So Order.Id alone can't be used to view someone else's receipt — you'd also need their Secret GUID, which isn't derivable from the order id/number. This already is effectively "an obscure/encrypted-strength reference," just implemented as a random GUID token appended alongside the id rather than as a single opaque token.
On your follow-up (exposing CompletedOrderId/CompletedOrderSecret in the URL):
This is a legitimate, narrower concern than "no auth at all" — it's about the secret being bearer-token-like and living in the URL. The token is not time limited as the receipt page should be accessible for some time. A leak or a guess is first of all not a security issue per se, and if you want you can move the receipt on another page carrying the checkout app and behind a permission check. Maybe combined with simple template logic that will time limit how long a receipt can be seen when anonymous.
BR Nicolai