open atlas
↑ Back to track
Offensive Security RED · 02 · 04

Auth bypass and session attacks

Authentication proves who you are once; the session carries that proof on every later request. Attackers rarely guess the password — they steal, forge, or replay the proof. See how, and why each control is the structural fix.

RED Middle ◷ 15 min
Level
FoundationsJuniorMiddleSenior

On an authorized engagement, a tester signs in to the target app, copies their own session token out of the browser, logs out, and pastes the token back into a fresh request. The app answers as if they were still logged in. That one observation tells them everything: the server never tied the token to the act of logging in — it tied identity to possession of a string. From the attacker’s chair, the password was never the interesting part. A password is checked exactly once, at the login wall, under rate limits and lockouts and maybe MFA. The session — the bearer credential the server hands back and then trusts on every subsequent request — is checked constantly, travels everywhere, and is usually guarded far less carefully than the wall it replaced. So real-world account takeover is rarely “guess the password.” It’s steal the proof, forge the proof, or trick the victim’s browser into spending the proof for you. This lesson is the attacker’s map of those three moves — bypass, hijack, and forge — read as the autopsy a defender does on their own auth code.

By the end of this lesson you’ll be able to explain how an attacker bypasses authentication, steals or forges a session, and abuses CSRF — and which structural control kills each move at the source.

Authorization first: a defender’s autopsy

Everything below assumes a signed engagement with explicit scope — a deliberately vulnerable lab, a CTF, your own application, or a bug-bounty program with the target in its asset list. Replaying or forging someone else’s session against a system you don’t own is unauthorized access in most jurisdictions, full stop; “I only used my own token” is not a defense once you point it at another account. We study the attacker’s reasoning for one reason: you cannot reliably close an auth flaw you only understand as a checklist item. No working tokens, victim cookies, or copy-paste exploits live here — only the mechanism, so you can recognize the gap in a code review and design it shut before anyone reaches it.

The shape of the problem: where the proof lives

Authentication and session management are two different jobs that beginners blur into one. Authentication is the one-time event at the login wall: prove you are who you claim, usually with a password plus maybe a second factor. Session management is everything after: the server issues a credential — a session id in a cookie, or a self-contained token like a JWT — and then trusts that credential to mean “this is the user who logged in” on every later request, because HTTP itself is stateless and remembers nothing.

That hand-off is the soft target. The login wall is hardened: rate limits, lockouts, MFA, breach-password checks. The session credential that the wall produces is a bearer token — whoever holds it is treated as the user — and it is replayed on hundreds of requests, cached in browsers, sometimes logged, sometimes put in a URL. An attacker who never touches the password but obtains, predicts, or fabricates that credential has the same access as the legitimate user. Three families of attack target this seam:

  • Authentication bypass — reach the authenticated state without completing the login.
  • Session hijacking — take over a valid session that belongs to someone else.
  • Session forgery — manufacture a credential the server will wrongly accept (the JWT pitfalls).

CSRF is a fourth move with a twist: the attacker never holds the credential at all — they make the victim’s own browser spend it.

Authentication bypass: reaching the inside without the wall

Bypass is the attacker reaching the authenticated state without satisfying the check the developer thought was mandatory. The recurring root cause is the same as the broader access-control failure: the application assumes a step happened instead of verifying it did.

  • Forced browsing / missing function-level checks. The login form gates the link to /dashboard, but /dashboard itself never re-verifies the session, so requesting it directly walks straight in. The “auth” was a hidden door, not a lock.
  • Logic flaws in multi-step flows. A password reset emails a token, but the “set new password” endpoint accepts a username and a new password without binding them to a valid, unconsumed, unexpired token — so an attacker resets any account. Or a multi-step login sets a “passed-first-factor” flag the client can flip, skipping MFA.
  • Trusting client-controlled state. A request carries role=admin or isAuthenticated=true in a cookie, header, or JWT claim the server reads without re-deriving it server-side. The client owns everything it sends; treating any of it as a verified fact is the bug.

The senior reflex is deny by default and verify every step server-side: every protected route independently re-establishes who the caller is and what they may do, computed from server-side session state — never inferred from the route being “behind” a login page or from a value the client supplied.

Session hijacking: stealing a valid credential

Hijacking takes over a session that is genuinely valid — the attacker doesn’t forge anything, they obtain the real bearer token. The interesting question for a defender is how the token leaks, because each leak path has a precise structural fix.

AttackHow the credential is obtainedThe structural fix
Sniffing in transitToken read off the wire on an unencrypted or downgraded connectionTLS everywhere + HSTS; Secure cookie flag so it never sends over HTTP
Theft via XSSInjected script reads the cookie or token from JSHttpOnly cookies (JS can’t read them) + fix the XSS at source
Session fixationAttacker plants a known session id, victim logs in under itRegenerate the session id on every privilege change (login)
PredictionSession ids are sequential or low-entropy, so they’re guessableCryptographically random ids with high entropy from a CSPRNG
Token in the URLSession leaks via Referer, browser history, server logs, shared linksNever put session tokens in URLs; keep them in cookies/headers

Two of these reward a closer look. Session fixation inverts the usual order: instead of stealing a token the victim already has, the attacker gives the victim a session id they already know (via a crafted link or a planted cookie), waits for the victim to authenticate, and — if the server keeps the same id across the login — inherits an authenticated session. The fix is one line of discipline: rotate the session identifier at every privilege transition, so the id the victim authenticates under is brand-new and unknown to the attacker. HttpOnly and XSS are a pair: a stored XSS that can run document.cookie turns every visitor’s session into a steal, which is why HttpOnly (the cookie is invisible to JavaScript) is the containment that decouples “we have an XSS bug” from “the XSS bug drains every session” — though it is containment, not a cure for the XSS itself.

JWT pitfalls: forging a credential the server accepts

A JWT is a self-contained credential: the claims (who you are, your role, expiry) travel inside the token, and the server trusts them because the token is signed. That design moves the trust boundary onto the signature — which is exactly where the classic forgeries live. From the attacker’s side, the question is always: can I get the server to accept a token I shaped?

  • The alg: none trap. Early JWT libraries honored a header claiming the algorithm is none — “this token is unsigned” — and accepted it as valid. An attacker edits the payload (e.g. role: admin), sets the algorithm to none, drops the signature, and the server trusts a token it never actually verified. The fix: the server pins the expected algorithm; it never lets the token’s own header choose how it’s verified.
  • Algorithm confusion (RS256 to HS256). When verification uses an asymmetric key (RS256), the public key is, by design, public. If the server naively verifies with whatever algorithm the header names, an attacker switches the header to HS256 (symmetric) and signs the forged token using that public key as the HMAC secret — which the server then “verifies” with the same public value. Same fix: pin the algorithm server-side; never derive it from attacker-controlled input.
  • Weak or leaked secret. An HS256 token signed with a guessable secret (secret, changeme) can be brute-forced offline; once the secret is known, the attacker mints any token they like. Fix: long, random, secret-managed keys — and rotation.
  • Ignoring exp / no revocation. A self-contained token is valid until it expires, and there’s no server-side list to revoke it. If the server forgets to check exp, a captured token is good forever; even when it checks, a stolen token is usable until expiry. Fix: enforce expiry, keep lifetimes short, and pair with a refresh/denylist mechanism for logout and revocation.
Why this works

Why is “let the token tell the server how to verify it” the bug behind both the alg: none trap and RS256-to-HS256 confusion? Because it hands the attacker control of the verification procedure, not just the data. A signature is only meaningful if the verifier independently decides what a valid signature looks like — which algorithm, which key. The moment the server reads the algorithm out of the token’s own (attacker-editable) header and obeys it, the token is grading its own exam: it can declare itself unsigned, or declare itself HMAC-signed so the public key becomes the “secret.” The structural fix is identical in both cases and has nothing to do with patching a library version: the server fixes the expected algorithm and key out-of-band and treats any token that doesn’t match as forged. Verification must be a property the server asserts, never a parameter the credential supplies — the same deny-by-default principle that runs through every auth control.

CSRF: making the victim’s browser spend the credential

CSRF is the elegant one because the attacker never steals or forges anything — they exploit the browser’s own helpfulness. The browser automatically attaches cookies to any request to a site, including a request triggered by a different site. So if the victim is logged in to bank.example and visits the attacker’s page, a hidden form auto-submitting POST bank.example/transfer rides along with the victim’s real session cookie, and the bank sees a fully authenticated, perfectly valid request — initiated by the attacker. The session was never compromised; its ambient authority was borrowed.

The structural fix attacks the gap directly: the server must require proof that the request came from its own front-end, which ambient cookies can’t supply. Two mechanisms, ideally layered:

  • Anti-CSRF tokens — the server embeds an unpredictable, per-session token in its own forms and requires it on state-changing requests. The attacker’s cross-site page can’t read that token (the same-origin policy blocks it), so it can’t include it, and the forged request is rejected.
  • SameSite cookiesSameSite=Lax or Strict tells the browser not to send the session cookie on cross-site requests in the first place, removing the ambient authority that makes CSRF possible. Lax is a strong, low-cost default; tokens remain the belt to SameSite’s braces.

Note the relationship: CSRF only works because the legitimate session is valid, so “harden the login” does nothing for it. It is defended at the request-acceptance layer, not the authentication layer — which is exactly why it’s its own category.

Pick the best fit

A bank's `POST /transfer` succeeds whenever a valid session cookie is present, with no other check. A tester demonstrates CSRF: a hidden auto-submitting form on an attacker page moves money using the victim's own logged-in session. Pick the fix that closes the class.

Quiz

A JWT library accepts a token whose header declares the algorithm as `none`, treating it as a valid unsigned token. Why is this exploitable, and what's the root fix?

Quiz

An attacker plants a session id they know into the victim's browser, the victim logs in, and the server keeps that same id — now the attacker shares an authenticated session. What is this, and what's the fix?

Order the steps

Order how an authorized tester reasons from a target login to account takeover via the session, then to the durable fix:

  1. 1 Authenticate, then locate the bearer credential the server trusts afterward (session cookie or JWT)
  2. 2 Probe how the credential is protected: is it tied to login, signed correctly, scoped to same-origin?
  3. 3 Exploit the weak link — replay a still-valid token, forge a JWT, or ride the session via CSRF
  4. 4 Close the class structurally: rotate ids on login, pin the JWT algorithm server-side, require anti-CSRF proof
Recall before you leave
  1. 01
    Why do attackers target the session rather than the password, and what are the three families of session attack plus CSRF?
  2. 02
    Explain the JWT forgery pitfalls and the single principle that fixes them, plus how CSRF works and why login hardening doesn't stop it.
Recap

Authentication proves who you are once, at a hardened login wall; session management is everything after — the server issues a bearer credential (a session id in a cookie or a self-contained JWT) and trusts it on every later request because HTTP is stateless. That seam, not the password, is where account takeover actually happens. Authentication bypass reaches the inside without completing login: forced browsing past routes that never re-verify, logic flaws in reset or MFA flows, or trusting role and auth state the client controls — fixed by deny-by-default verification of every step server-side. Session hijacking steals a genuinely valid token via sniffing, XSS, session fixation, prediction, or URL leakage, and each path has a precise structural fix: TLS plus HSTS and Secure cookies, HttpOnly cookies, rotating the session id at every privilege change, high-entropy ids, and never putting tokens in URLs. JWT forgery comes from letting the token choose its own verification — the algorithm-none trap and RS256-to-HS256 confusion both fall to one rule: the server pins the algorithm and key and treats any mismatch as forged, alongside strong secrets and enforced expiry. CSRF needs no stolen credential at all; it makes the victim’s browser spend its own session via the auto-attached cookie, so it’s defended at request acceptance with anti-CSRF tokens and SameSite, not at the login wall. So the next time you read auth code, the attacker’s question turned inside out is your reflex: after login, what exactly does this server trust — and could a string a client holds, shapes, or rides be enough to be the user?

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 6 done
Connected lessons

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.