Field notes from an authorized audit of a small web store. The headline: there was no backend to attack, so the real findings were identifier manipulation (business logic) and clickjacking.
Setup / hypothesis
- Small store on Vercel: catalog, product pages, cart, share-cart URLs, contact buttons.
- Looked like Next.js. Turned out to be a React + Vite SPA — the initial misread that set the approach.
- Mindset: from "how do I protect this?" to "how can I break it?"
Step 1 — Recon (domain only)
-
robots.txt,sitemap.xml, routes and params, product/cart flows, HTTP headers. - Result: 0 findings. No magic
/admin, nothing in the sitemap.
Step 2 — "Where's the server?"
Expected /api/products, /api/cart. They did not exist.
$ curl -s https://TARGET/api/products
→ 404
The app was a SPA with no server and no database.
Implication for the scope: no server-side attack surface → no SQLi, no auth-bypass/authorization against an API, no server-side HTML injection. When you can't attack an API, you attack the assumptions of the app.
Step 3 — ID manipulation
Walk identifiers through real flows: /producto/1 → 2 → 3 …
Finding 1: products shown as sold out became reachable by changing the ID within certain flows.
Classification note (do this in your own reports): this is NOT classic IDOR. IDOR means a server protects a resource; there is no server here. The precise label is identifier manipulation + insufficient business-logic validation. Classifying correctly is security work.
Step 4 — Share-cart tampering
Share-cart URLs could be modified to introduce sold-out products. The logic accepted states the owner never intended (a stock state the business had ruled out).
Step 5 — Headers
$ curl -I https://TARGET
X-Frame-Options: (absent)
Content-Security-Policy: frame-ancestors (absent)
The app could be framed.
Step 6 — Clickjacking + combined PoC
<iframe src="https://TARGET"></iframe>
It loaded. The store was embeddable.
Combined PoC: external page loading a tampered cart URL in an iframe + own visual elements on top.
Scoped results
Not obtained: passwords, RCE, server access, DB, control of the app.
Demonstrated: state manipulation, manipulable cart, embeddable app, and the combination. Business angle: a third-party page rendering the legit store inside it → price/availability confusion, loss of trust, visual impersonation, complaints hitting an innocent owner.
The patch
X-Frame-Options: DENY # or CSP frame-ancestors 'none'
# business logic: stop trusting client data; validate availability on every flow
Retest
Retried the attack after the fix → iframe no longer loads. Prefer "I tried again and it no longer works" over "I think it's fixed."
Lessons
- Architecture = attack surface. React + Vite ≠ frontend + API + backend + DB, even if the customer sees the same shop.
- Scanners miss business logic. No tool asks "should I be able to add a sold-out product to the cart?"
- Attacks start with small questions. Change the ID. Change the URL. Frame the page. Then combine.
AI was used as a second opinion (stack identification). The decisive question stayed human: "What happens if I use this functionality in a way the developer didn't expect?"
Adapted from my original post on TallerWeb.
Top comments (0)