Stillwater Co-op Bank
A small member-owned community credit union's online portal. The member dashboard, staff back office, and wire-approvals queue all ride on the same in-house auth layer that nobody on the team has audited since 2019.
The Scenario
Stillwater Co-op Bank has served its community since 1958 — four branches across two counties, twelve thousand members, share-draft accounts and small consumer loans only. The online portal was built one summer by the treasurer's nephew and bolted onto the back-office wire-approvals queue a few years later when remote staff outgrew the paper log. The board's compliance review last quarter flagged the whole stack as "long overdue for outside eyes."
Challenge Intel
Synopsis
The JWT verifier reads the kid header as a filesystem path. Point it at a static asset you can fetch over HTTP, use the asset's bytes as the HMAC secret, and forge an admin token.
What It Is
On login the server issues a JWT with header {"alg":"HS256","kid":"2024-q4"} signed using the contents of /app/keys/2024-q4.pem as the HS256 secret. The verifier does `open(f"/app/keys/{kid}").read()` with no normalisation, so kid can traverse out of /app/keys into any readable file in the container. /static/style.css is served by Flask and is byte-identical to the on-disk file the server reads from inside the container, so the player can fetch it, use it as the HMAC secret, and forge a token that the server happily verifies.
Who It's For
Brand-new JWT players. Familiarity with base64-decoding a JWT and PyJWT (or jwt.io) is enough.
Skills You'll Practice
- Inspecting and decoding a JWT cookie
- Recognising filesystem paths in JWT header fields
- Path traversal into a known-readable asset
- Forging an HS256-signed token with PyJWT
What You'll Gain
- kid is an arbitrary string under the issuer's control — never treat it as a filesystem path
- Any public asset served by the application can become a known-plaintext HMAC key
Ready to hack Stillwater Co-op Bank?
This challenge is free. Sign up and start hacking.