Easy Logic Bugs: How I Bypassed Two “Unbypassable” Checks in Production Systems
by Ziad Mohammad — Bug Hunter & Security Researcher
There’s a myth in security research that the best bugs require exotic payloads, zero-days, or deep reverse engineering. Sometimes the best bugs are the opposite: a server that trusts the client a little too much, and a rule that’s enforced in the wrong place.
Here are two real-world examples I found — both business logic flaws, both patched through the applications’ normal flows, and both reduced to “just don’t check the thing where it matters.” Target names are withheld; the mechanics are what matter here.
Bug #1: The Discount That Wouldn’t Die (E-commerce Platform)
A major online retailer ran an opt-in “extra deals” campaign: a 20% discount, gated behind a simple rule — minimum 2 items, minimum €69 total. Try to check out with less, and a dialog pops up:
“Below minimum amount — Shop minimum 2 items for minimum 69 € to use the extra deals voucher. By continuing to checkout the discount will be deactivated.”
Click “Continue,” and sure enough — the discount vanishes. Total goes back to full price. Rule enforced, as designed.
Except it wasn’t enforced. It was performed.
The deactivation logic lived entirely behind that dialog’s “Continue” button — a client-side action. So I asked the obvious question: what happens if I just… don’t click it?
The bypass:
- Add one qualifying item to the cart (a €99.99 item).
- Opt into the campaign. Cart confirms: “Your discounts are active.”
- Instead of clicking Checkout from the cart, type the checkout URL directly into the browser.
No dialog. No check. The checkout loaded fully order-ready — billing form, delivery options, payment selection — with the 20% discount still applied to a single item. €99.99 became €79.99. The discounted total wasn’t a UI glitch either; it was baked into the server-side checkout session and survived full page reloads.
Why it worked: the eligibility rule was enforced reactively, triggered by a specific client-side interaction, instead of being validated structurally every time the checkout state was built. Any path that skipped the dialog — a bookmarked URL, a typed address, a browser autofill suggestion — skipped the rule entirely.
The fix I recommended: validate campaign eligibility server-side at checkout construction (and again at order placement), based on actual cart state — item count and total — not on which button the user happened to click.
Severity: Medium.
Bug #2: Cancelling the “Non-Cancelable” Booking (Hotel Booking Platform)
The second bug lived in a booking cancellation API, and it’s an even more classic example of the same disease: the server trusted an identifier it should have re-validated.
The cancellation request looked like this:
POST /api/.../cancelBooking?url=.../bookings/cancellation/[BOOKING_ID]Nothing unusual — a standard authenticated cancellation call, with the booking ID embedded in a URL parameter.
Get Ziadmohammad’s stories in your inbox
Join Medium for free to get updates from this writer.
The setup: two bookings under one account.
- Booking A — eligible for cancellation.
- Booking B — explicitly not eligible. Deadline passed, flagged as non-cancelable.
The bypass:
- Start a legitimate cancellation for Booking A and intercept the request.
- Swap
[BOOKING_A]for[BOOKING_B]— nothing else changes. Same session, same auth, same everything. - Forward the request.
Response:
json
{"status":"Cancelled Booking"}Checked the booking record afterward:
json
"status": "Cancelled Booking",
"non_cancelable": trueNot a cosmetic error message — an actual state change. A booking explicitly marked non-cancelable was cancelled, because the endpoint checked “does this user own a booking” but never re-checked “is this specific booking actually eligible for cancellation right now.”
This is textbook IDOR-meets-business-logic: the authorization check (is this your booking?) passed, while the authorization check that actually mattered (is this booking in a cancellable state?) was never run.
Severity: Medium — low complexity, no user interaction required, real integrity impact on the booking record.
The Pattern Underneath Both Bugs
Strip away the specifics and both reports say the exact same thing:
A rule was enforced at the point where the user usually interacts with it — not at the point where the system actually commits to it.
- The e-commerce platform enforced the discount rule inside a dialog’s click handler, not inside checkout construction.
- The booking platform enforced cancellation eligibility (implicitly) during the “normal” cancel flow, not inside the endpoint that actually performs the cancellation.
Neither bug needed fuzzing, injection, or a single exotic tool. Just:
- Find the “normal” path and watch where the check happens.
- Find an alternate path to the same server-side effect.
- See if the check comes along for the ride.
It usually doesn’t — because developers test the happy path, and the happy path is exactly where the validation looks like it’s working.
Takeaway for Builders
If you’re building anything with conditional pricing, cancellation windows, eligibility gates, or any rule that can be expressed as “if X, don’t allow Y” — ask where that check actually lives:
- Is it re-evaluated every time the server constructs the relevant state (checkout, booking status, order)?
- Or does it only fire in response to one specific client action?
If it’s the second one, you have exactly the bug class above, and someone will find it — because, as shown here, it doesn’t take much.





