Engineering

Our review said fine. The audit said otherwise.

A stored XSS nobody would have guessed, a rate limit defeated by one HTTP header, and a 404 that answered 200 — with the fix for each.

Mayank Batra
October 13, 2026
5 min read
0 views
security
audit
seo
What an independent security and UX audit found that our own review did not

What an independent security and UX audit found that our own review did not

We ran two audits against this site — one offensive, one about content and interaction — and then tried to break our own findings. Three of them are worth publishing because each one is a class of mistake, not a one-off bug.

1. Stored XSS through JSON-LD

Structured data is JSON, and `JSON.stringify` does not escape the `<` character. A CMS field containing `</script>` therefore closed the script tag early and everything after it executed as markup. Our own review had looked at the CMS validation and the rendered HTML — both fine — and missed the serializer. The fix is one function: escape `<`, `>` and `&` when serialising JSON-LD. If you render structured data from any user-editable field, check this today.

2. A rate limit defeated by rotating one header

Our login limiter keyed on the client IP, which it read from `x-forwarded-for`. Rotating that header gave the attacker a fresh bucket per request — seven attempts, never a 429. The fix is two parts: only trust proxy headers when a trusted proxy is declared, and add an IP-independent ceiling that no single caller can dodge.

3. A 404 that answered HTTP 200

Unknown service URLs returned the not-found page with a 200 status, which teaches search engines that the page exists. The cause was not the routing: a route-level `loading.tsx` streamed the response shell, committing the status before `notFound()` could run. `dynamicParams = false` and a `generateMetadata` guard both failed to fix it; removing the streaming boundary did.

What we changed about our process

  • **Check the serializer, not just the input.** Validation and escaping are different jobs.
  • **Any limit keyed on a client-supplied value is not a limit.**
  • **Test status codes, not just page content.** A page that renders the right thing with the wrong status is still broken.
  • **An audit that only confirms your own review was not an audit.** The value is in the findings you argued with.
Share

Share this content

A

Mayank Batra

Avartana Labs Editorial Team

Newsletter

Stay Updated with Our Latest Insights

Get exclusive content on design, development, and digital innovation delivered to your inbox.

We respect your privacy. Unsubscribe at any time.