Skip to content
Trust no request
Security series · stage 2 of 2 · 10 chapters · 229 minutes

Trust no request

Stage 2 of a hands-on security series. One small Python service on your own machine, ten real web weaknesses, and a check that proves each fix: SQL injection, XSS, CSRF, IDOR, broken access control, SSRF, path traversal, mass assignment and open redirects.

New here? Stage 1, How systems talk, covers DNS, TLS, cookies and sessions. This stage is the application on top.

POST /loginone input, two readings: data or code

built from text

SELECT id FROM users WHERE email = 'x' OR '1'='1' -- ' AND password = 'anything'
Bypassed: signed in as u_10413 rows

bound parameters

SELECT id FROM users WHERE email = ? AND password = ? -- bound: [email, password]
Rejected0 rows

The same input. On the left it is pasted into the query text, so a quote can end the string and the rest becomes query. On the right it is bound as a value, so it only ever matches a row or does not.

The lab

Ten cases, one per chapter

Each case is one small service with one deliberate weakness, an attack that runs only on 127.0.0.1, a fix you write, and a check that rejects the lazy non-fix. Grouped from the foundations to what senior engineers still get wrong.

01

Foundations

Untrusted input becomes code: injection and cross-site scripting.

02

Access and identity

Who may touch what: object and function access, forged requests, over-posting.

03

Server-side and redirects

The server acting on a request: its network, its files, and where it sends you.

Measured by the lab

Numbers from real runs

The four try experiments measure the attacks and the defences on your own machine. These figures come from the runs the workshop was written from.

3
Tokens dumped through the login

every user token recovered in 3 requests and 581 bytes (try exfiltrate)

3 of 3
Rows a string-built query leaks

the OR-always-true email returns every user; bound parameters return 0 (try inject)

142,144
Collisions in 200,000 weak tokens

a predictable scheme repeats; token_urlsafe(24) repeats 0 times (try tokens)

3 of 6
Internal URLs a blocklist lets through

an allowlist lets 0 of 6 through on the same URLs (try ssrf)

Quick start

You need uv and git

uv installs Python for you, and the lab uses only Python's standard library. Every service binds to 127.0.0.1 and nothing leaves your machine.

shell
git clone https://github.com/jars-demo/web-security-demo.git
cd web-security-demo/lab
uv sync
uv run python -m trust run 1

The series

  1. Stage 1

    How systems talk

    Stage 1

  2. Stage 2

    Trust no request

    You are here