Sessions, tokens and access control
Read and forge JWTs and Flask sessions, break the assumptions behind a session cookie, and win the races that a request boundary creates.
Assumes3. Hashes, identification and cracking12. Client-side: XSS and the browser's trust model
By the end you can
- Decode a JWT and identify the attack its header enables
- Forge an alg=none token and recover a weak HMAC secret offline
- Unpack and re-sign a Flask session once the secret key is known, and find that key first
- Choose between horizontal and vertical access-control tests, and prove each with two accounts
- Exploit a check-then-act window with concurrent requests, and explain why a retry loop is not the same thing
- Recognise a request-smuggling primitive from a header pair a proxy and a server read differently
1. Read
Attacking JWTs: alg=none, algorithm confusion, and the header fields nobody audits
A JSON Web Token is a signed claim you were handed and asked to give back. Every classic JWT bug is a place where the verifier lets the token choose how it is verified - alg=none, RS256 to HS256 confusion, kid injection, and attacker-hosted key URLs.
Sessions, cookies, CORS and CSRF: the browser's trust rules
Which origin can read what, why a cookie is scoped differently from everything else in the browser, and the four ways a session is stolen without ever finding an XSS: CSRF, a permissive CORS policy, cookie tossing, and session fixation.
Race conditions: spending the same balance twice
Limit overruns, TOCTOU on the filesystem, and the single-packet attack that removes network jitter from the equation. How to recognise a race in a feature description and how to actually win one.
Request smuggling: when the proxy and the server disagree
CL.TE, TE.CL, TE.TE and the HTTP/2 downgrade desyncs. How two servers reading the same bytes can disagree about where one request ends, what that buys you, and how to detect it without wrecking the target.
2. Use the tools
In the order they come up while solving. Read what each one does, or go straight to the workspace tab that runs it.
- JWT decoder and signature verifier
Decode a JSON Web Token’s header and payload and verify HS256/HS384/HS512 signatures against a known secret - all locally.
Open it in the workspace - JWT alg=none bypass generator
Forge an unsigned JWT by setting the algorithm to none, and understand why some libraries still accept it.
Open it in the workspace - JWT secret brute force
Recover a weak HMAC signing secret from a JWT by testing a wordlist against the token’s own signature, in the browser.
Open it in the workspace - Flask session cookie decoder
Decode and verify Flask’s itsdangerous session cookies, with automatic zlib detection and both key-derivation schemes.
Open it in the workspace - HTTP request replayer
Craft and replay HTTP requests with arbitrary methods, headers, and bodies, and read the raw response - a Repeater that runs in your browser.
Open it in the workspace - HTTP security header analyzer
Analyse CSP, HSTS, X-Frame-Options, and CORS headers on a response - and find the gaps in a Content-Security-Policy that make XSS exploitable.
Open it in the workspace
3. Try one now
Generated in your browser and checked in your browser. No account, nothing to download, and a fresh one whenever you want another.
4. Practise on the real thing
Real picoCTF challenges that use these techniques, easiest first. 19 match in total - see the full index.
Common mistakes
The wrong turns this topic reliably produces. Written as the mistake rather than the rule, because the rule is easy to agree with and easy to walk straight past.
- Editing the payload of a signed token and expecting it to be accepted. The attack has to defeat the signature - alg confusion, a known secret, or a kid that points somewhere useful - not ignore it.
- Decoding a Flask session and calling it forged. It is signed too; without the secret key you have read access and nothing more.
- Testing a race with a for loop. Sequential requests never overlap; the window needs concurrency, and often needs the requests to arrive in the same packet.
- Cracking an HMAC secret against re-encoded JSON. The signature covers the base64url header and payload exactly as transmitted, so pretty-printing or reordering the claims before testing candidates makes the correct secret look wrong.
- Fixing an expired token by editing exp and nothing else. Expiry is checked after the signature, so a token that fails verification never reaches the claim you changed and the error tells you nothing about it.
Checkpoint
Take a JWT-protected endpoint and reach an admin-only response, stating which of the three token weaknesses you used and why the other two did not apply.
Teaching note
Students conflate 'I can read the token' with 'I can change the token'. Decode a JWT in front of them, edit the role claim, watch the server reject it, and only then introduce the three ways the signature actually fails. The rejection is the lesson.
Go deeper
The lessons above are written to get you through a challenge. These go after the subject instead. Each one opens our notes on that chapter - what it argues, what to take from it and where it stops - so this is somewhere to read now rather than a book to buy first. Nothing here is affiliate-linked or sold by us.
Chapter 8, Attacking Authentication
Hacking APIs - Corey Ball
Token handling as an attack surface in its own right, including the JWT cases in deployment terms.
Chapter 10, Exploiting Authorization
Hacking APIs - Corey Ball
The two-account method for proving an access-control bug, which is what turns a suspicion into a finding.
Chapter 15, Race Conditions
Real-World Bug Hunting - Peter Yaworski
Real reports where the whole bug is a window of a few milliseconds.
Chapter 20, Single-Sign-On Security Issues
Bug Bounty Bootcamp - Vickie Li
Where session material crosses a trust boundary between two systems, which is where most token bugs actually live.
Every book the curriculum cites has a page in the library.