Skip to content
Z3tra
All articles
3 min read

Understand the application before you test it

Scanners find what they were told to look for. The bugs that matter live in the gap between what an application believes about itself and what it actually enforces.

The fastest way to waste a week on a web application is to point a scanner at it and start reading output. You get a wall of findings, most of them noise, and none of them the authorisation flaw sitting three clicks into the account settings.

The habit that actually works is slower to start and much faster to finish: understand the application first, then look for the places where its own model of itself does not hold.

What "understand it" concretely means

Not "click around for a bit". Four specific questions, written down.

What is it trying to do? Not the marketing description — the transaction. An invoicing tool moves money between parties who do not trust each other. A support desk lets strangers write into a system staff will read. That framing tells you where the interesting failures will be before you have sent a single request.

Who is meant to be able to do what? Every role, every object type, every verb. This is the matrix that most applications get wrong somewhere, and you cannot notice a missing cell in a matrix you never drew.

What state does it hold, and where? Session, tokens, server-side records, client-side caches, third-party stores. State that lives in two places is state that can disagree.

Where does trust change hands? Between the browser and the API. Between the API and a queue. Between the application and an integration that authenticates once and is trusted forever afterwards. Boundaries are where assumptions get dropped.

Then test the model, not the surface

Once you have the matrix, testing stops being exploratory and becomes systematic. You have a list of things the application claims. Each one is a hypothesis.

Map the object identifiers

Every resource has an id somewhere — a path segment, a query parameter, a field in a JSON body, a value inside a JWT. Collect them. These are the inputs to every access-control test you are about to run.

Establish two accounts in the same role

Almost every meaningful authorisation test needs two peers. One account proves nothing; you cannot distinguish "allowed" from "not checked".

Replay every request as the other account

Same request, other session. If it succeeds, the check is missing. If it fails, note how — a 403 and a 404 tell you different things about whether the object was looked up before or after the check.

Then go down a role

Repeat with a lower-privileged account. Then with no session at all. The most common finding is an endpoint that checks authentication and forgets authorisation.

The part people skip

Read the client-side code. Not to find secrets in it — although you will — but because a single-page application ships you a fairly complete description of the API it talks to, including the endpoints the interface never shows you.

# Pull the bundles, then look at what the app knows about itself
ffuf -u https://target/_next/static/chunks/FUZZ -w chunks.txt -mc 200

A route table in a JavaScript bundle will list admin paths that no link in the UI points at. Those paths still exist on the server. Whether they are protected there is the actual question.

Why this beats starting with tools

Tools are excellent at the classes of bug someone already characterised. They are useless at the ones that depend on knowing that a project_id in this application means something different in the reporting module than it does in the billing module. That kind of finding comes from the model, and the model comes from reading.

The tools still run. They just run second, and against a target you can already reason about — which means you can tell a real finding from a false positive without spending an afternoon on it.

Related

Article4 min

IDOR is still everywhere, and here is why

Broken object level authorisation stays the most common serious finding in web applications. Not because it is hard to fix, but because of where the check has to live.

  • Web Security
  • OWASP
  • Bug Bounty
Article2 min

The JWT mistakes that still work in 2026

Algorithm confusion, unverified signatures and secrets that were never secret. A tour of the JWT failures I keep finding in labs, and what each one actually requires to exploit.

  • Web Security
  • JWT
  • Authentication
Article3 min

Building a CTF platform taught me more security than solving CTFs

Running code that is designed to be attacked forces a kind of threat modelling that solving challenges never does. Notes from building Hackuten.

  • Web Security
  • Research
  • Docker