From Zero to P1: A Writeup of a Critical Authentication Bypass
October 01, 2026

From Zero to P1: A Writeup of a Critical Authentication Bypass

The 401 was the least interesting part of that request. What held my attention was the line I deleted from it: a header lifted out of the mobile app's traffic, one that appeared in no API document. Ten minutes later, the same header — no token, no session, nothing — returned another user's profile with a 200. This is the path from recon to a P1, including the report that got it there. Names and domains are anonymized; the technique is not.

Recon: Follow the Client, Not the Docs

Public documentation tells you what a platform intends to expose. Client code tells you what it actually calls. When those two disagree, the gap is where the good bugs sit.

The target was a mid-size B2B SaaS product: a web dashboard, a mobile app, and a REST API with a published reference. I spent the first day doing boring things. Read the program policy twice and wrote down exactly what was in scope. Enumerated subdomains. Resolved them. Then I did the part most hunters skip:

  • Downloaded the mobile build and walked every screen through a proxy.
  • Pulled the web app's JavaScript bundles and searched for endpoint paths, header names, and fetch calls.
  • Diffed the hosts I had found — production, a staging alias, and one internal-looking name that answered on the same edge.
  • Kept a running list of headers the clients sent that the documentation never mentioned.

That last list is what mattered. The mobile app sent a header the web app didn't, on nearly every request. It looked like telemetry. It wasn't.

Spotting the Trust Boundary

The architecture was the usual shape: an API gateway in front, a handful of services behind it. The gateway validated the bearer token, then forwarded the request upstream with the caller's identity attached in internal headers — a user ID, an organization ID, a role. Backend services trusted those headers because, from their point of view, only the gateway could set them.

Almost. On the current route prefix, the gateway stripped any inbound copy of those headers and wrote its own. On a legacy prefix that still routed to the same upstream service, the stripping rule had never been applied. The backend was listening on the same port either way.

So the question was simple: what happens if I send the identity header myself, to the route the gateway does not clean?

Turning a 401 Into an Authenticated Request

Baseline first. An unauthenticated request to the legacy "me" endpoint returned 401. Good.

Then I added one header containing a numeric user ID and dropped the Authorization header entirely. 200 OK, with a full user object. The application had not only skipped authentication — it had built the entire request context from a value I controlled.

Prove it with accounts you own

This is where discipline matters more than curiosity. Sequential IDs meant I could have walked straight into someone else's account. I didn't. Instead I registered two accounts I controlled, in two separate organizations, and used the header to read account B while authenticated as nobody. Cross-tenant read, proven, with only my own data involved.

Write access came next, and I tested it the same way: a rename on an object belonging to my second account. It worked. No authorization check anywhere in the path.

Proving Impact Without Breaking Anything

A bypass is only worth what you can show. Before I touched the report, I collected proof a triager could verify in under a minute:

  1. Raw requests with visible timestamps, showing the 401 baseline next to the 200 bypass.
  2. A short recording of the same request from a clean browser profile with no cookies.
  3. Confirmation that the identity header accepted arbitrary IDs, not just mine.
  4. A note on what I deliberately did not do — no enumeration, no reads outside my two test accounts.

That last item is not decoration. Programs read it. It tells them you understand the line between demonstrating a bug and exploiting customers.

The Report That Earned the P1

Reports get triaged by people with a queue. Lead with impact, not with your journey.

My summary read roughly like this:

An unauthenticated attacker can impersonate any user, in any organization, by sending a single request header to a legacy API route. Read and write access to tenant data is possible without credentials.

Then the body, in this order:

  • Severity rationale: no authentication required, cross-tenant scope, write capability, affects every customer.
  • Numbered reproduction steps with exact requests and responses.
  • Evidence, with other users' identifiers redacted.
  • A short root-cause note: the header-stripping rule covers one route prefix but not the legacy rewrite to the same service.
  • Remediation: strip client-supplied identity headers at the edge for every prefix, and have services verify a signed internal token instead of trusting a bare header.
  • A timeline of discovery and testing.

It came back P1, was patched quickly, and confirmed by replaying the exact requests from the report. The root cause was a configuration rule that covered one path and not its twin — a five-minute fix sitting behind an old assumption.

Why It Landed at P1

The severity was not about cleverness. It was about reach: no credential needed, any tenant reachable, a write path available, exploit complexity near zero. A header leak that exposes an internal hostname is a P4.

Photo: Boskampi / Pixabay

Previous Post

Server-Side Request Forgery (SSRF) Explained: From Detection to Exploitation

Next Post

How to Automate Your Recon with Subfinder, httpx, and Nuclei

Related Posts

About Us

Bug Hunter Journal

Bug Bounty

Notes from the front lines of bug hunting.

Read More

Latest Post

Understanding CVSS Scoring: How to Rate Your Bugs Like a Pro
Transitioning from IT Security to Full-Time Bug Bounty: A Realistic Roadmap
How to Automate Your Recon with Subfinder, httpx, and Nuclei
From Zero to P1: A Writeup of a Critical Authentication Bypass

Notes from the front lines of bug hunting.