docs

Authorize (access control)

Find broken access control by replaying captured flows across identities and mutations — prove an IDOR or privilege escalation by showing one user's request returning another user's data. Pro.

Authorize is Hugin's broken-access-control (BAC) engine. It finds the bugs where a request works for someone it shouldn't: IDOR, privilege escalation, cross-tenant access, and missing function-level authorization. You hand it a set of identities and a set of captured flows; it replays every flow as every identity, mutates the ids, roles, verbs, and scopes, and compares the responses. A finding is proof, not a guess — user A's request returning user B's data, baseline and replay side by side. Authorize is Pro.

The Authorize view showing the identity-by-flow authorization matrix
Replay every captured flow as every identity, then read the matrix — a cell that should be blocked but comes back 200 is the finding.

Two halves

Passive signals are raised for free as you browse. A role or tenant field in a response body, a predictable id, an endpoint that answers the same with or without auth, a response shape that converges across users, a header that flips a decision, a request field echoed back, a SAML assertion worth a manual look. They do not prove a bug — they mark where to point the active audit, so the scan is corpus-driven rather than blindly exhaustive.

Active audit is the core. You define identity profiles, then Hugin replays captured flows across them and across mutations and reads the responses against your rules. This is the half that produces findings.

Define your identities

An identity profile is the credential set Hugin replays as: its cookies, headers, and bearer token, plus an expected role — admin, user, guest, anonymous, or custom. Mark one profile as the baseline; it is the anchor every replay is compared against. Add an anonymous profile that strips auth entirely — it is the fastest way to catch an endpoint that answers anyone. Each profile can carry a host scope so one vault rides across several targets without firing every identity at every host.

The matrix is only as honest as its sessions. Bind a login macro to each identity so its token refreshes automatically mid-run — see Macros and session rules. After 2 consecutive 401/403 or redirect-to-login responses an identity is marked stale and skipped, so a long run keeps firing the live identities instead of testing the login wall with a dead one.

The check catalog

Each check toggles independently, so you can run the whole catalog or isolate one class. By default a check only fires on flows that fit it (JWT escalation on JWT flows, OAuth scope on /token, GraphQL on GraphQL endpoints); flip force-enable all when you know the target supports a scheme the captured traffic hasn't shown yet.

IDOR via path parameter

Swap an id in the path (/users/123 → a peer's id). A 2xx means you read a resource that isn't yours.

IDOR via query or body parameter

The same swap in a ?id= query or a body field, for endpoints that key the object off the parameter instead of the path.

Response body matches across identities

Replay the same URL as two different users and get identical data back — the classic /api/Users/:id leak that id-mutation checks miss because no id changed.

Cross-tenant access

Rotate a tenant or org id and land on another tenant's data. The boundary crossed is the organization, not the user.

Auto-detect IDOR (id corpus)

Rotate every id Hugin collected while you browsed across every identity, so stored resource references get tried against users who shouldn't see them.

Function-level authorization bypass (BFLA)

Replay a privileged request unchanged as a strictly-lower-privilege identity. A 2xx means a low-priv role reached an admin function — the role boundary failed, not the resource one.

Authorization bypass via header

A trusted-proxy header (X-Forwarded-For, X-Original-URL, and friends) flips a 401/403 into a 2xx — the app trusts a header an attacker controls.

HTTP method tampering

The same URL answered with an alternate verb when the authz middleware only guards the captured method, leaving the alternate-verb handler exposed.

Role-name enumeration / privilege escalation

Swap a client-supplied role value (role=user → role=admin, is_admin=false → true) and get a different 2xx — the server trusts the privilege you state.

Mass-assignment privilege escalation

Inject a privileged field the request never carried (isAdmin, role, permissions, isVerified) and watch the server accept or echo it.

JWT claim or scope escalation

Tamper a JWT claim or scope and have it honoured without re-auth — a signature or verification flaw in the token path.

OAuth scope elevation at /token

The authorization server hands back a token with the elevated scope you asked for rather than the one the client is registered for. No forgery — it just trusts the parameter.

Content-Type polyglot

Re-send a JSON body as XML or form-urlencoded and get the same result, bypassing authz rules that are enforced per request shape.

Sensitive endpoint reachable without authentication

The anonymous replay returns the same protected data the authenticated baseline did — the endpoint has no auth check at all.

Rate-limit bypass via auth-state change

A captured 429 clears to 2xx when the token changes — the limiter is keyed to the session, so rotating tokens defeats it.

GraphQL introspection probes

On GraphQL endpoints, mine the schema by introspection and probe sensitive or admin-only fields across identities.

Telling a real block from a decoy

A 200 is not always a leak and a 403 is not always a block. Hugin already reads the denial: 401 (not authenticated) versus 403 (authenticated but forbidden) versus a 404 that masks a resource another identity got a 200 for, versus a 3xx to a login page. On top of that, enforcement rules let you pin what a block and a bypass look like on this specific target. Each rule matches on a status code, a header, a body-contains string, a body regex, or a body length, then declares the response enforced or bypassed. That turns "is this 200 a leak or a soft error page?" into a deterministic verdict per target instead of a judgement call per flow.

To stop dynamic noise from breaking the body comparison, add ignore patterns that mask CSRF tokens, nonces, timestamps, and request-ids before Hugin diffs two responses.

Running an audit

  1. Load your identities

    Add a profile per identity with its cookies, headers, or bearer token; set the expected role; mark the baseline; add an anonymous profile. Bind a login macro to each so the matrix doesn't die on an expired session.

  2. Pick the flows

    Select flows from History, or leave the set empty to audit every in-scope flow in the project. Endpointer-seeded flows are already in the corpus, tagged and ready.

  3. Choose the checks

    Toggle the catalog above to taste. Set per-target enforcement rules and, if needed, endpoint-specific similarity thresholds.

  4. Set the budget and pace

    Cap the run with a request budget (5,000 by default) and a per-probe delay to stay under rate limits. The body-similarity threshold defaults to 0.9; tighten it if a target's responses are noisy.

  5. Pick the comparison mode

    Pairwise compares the baseline against each identity — the cheap default. Full matrix compares every ordered pair, for an N-way admin × manager × user × anonymous audit. Then run it.

You can replay through Hugin's proxy so the audit's own traffic lands in History under your scope and rules. Watch the run with the live progress counters, and cancel a run that's drifting wider than you intended.

Reading a finding

Every finding shows the baseline and the replay flow side by side — the Original, Replayed, and Diff panes — with a one-line evidence string such as 200 as user-b vs 403 as anonymous, body 4129 == 4129 bytes, so the proof is in the finding, not in your memory of the run.

Each IDOR-class finding is tagged horizontal or vertical. Horizontal is peer-to-peer access of a same-role resource (path-param IDOR, cross-identity echo, cross-tenant). Vertical is privilege escalation (header bypass, JWT, role, OAuth, auth-optional leak, verb tampering, content-type polyglot). Generic query/body parameter mutation is left undetermined for you to label.

Severity follows the bug. The hard access-control breaks — header bypass, cross-tenant, mass assignment, JWT, path-param IDOR, OAuth scope, verb tampering, BFLA — land Critical. Cross-identity echo, parameter IDOR, auth-optional leak, and rate-limit bypass land High. Status divergence, role escalation, and content-type polyglot are Critical when the replay body matches the baseline (same data leaked) and High otherwise. Confirmed findings flow to Findings for triage.

From Endpointer to Authorize to YesWeHack

Endpointer is the input side: it probes which endpoints enforce auth and seeds the gated ones — with Nerve parameter signals — into the BAC corpus. Authorize is where the cross-identity replay runs against that corpus. When a finding holds up, hand it to YesWeHack; Authorize pre-selects the bug type from the finding's class (IDOR findings map to CWE-639, the rest to the access-control buckets) so you're not re-deriving the CWE by hand.

Mutations can synthesize destructive verbs (PUT/PATCH/DELETE) that persist writes against the target. That is off by default — verb tampering only retries a safe POST until you opt in. Turn it on only for an engagement you're authorized to break, and keep the whole audit inside scope.

Last updated 2026-06-17.