JWT Secrets
JWT Secrets
Platform: cryptohack | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-06-21 | Status: Solved Techniques: admin_privilege_escalation, hs256_resign, jwt_forgery, weak_secret_guessing
Summary
Task: a CryptoHack JWT challenge issues and verifies HS256 tokens, with the flag gated behind admin:true; source comment hints the secret is the PyJWT readme example key. Solution: guess the default HS256 secret 'secret', forge a token with admin:true, and submit it to the authorise endpoint to recover the flag.
JWT Secrets — CryptoHack
Description
A CryptoHack "Crypto On The Web" challenge about JWT signing algorithms. Background text explains HS256 (symmetric HMAC-SHA256) vs RS256 (asymmetric RSA), and warns that developers sometimes use default or weak HS256 secret keys. The page provides source code with a
create_session(username)endpoint and anauthorise(token)endpoint, plus a suspicious comment about the secret key.
Challenge URL: https://web.cryptohack.org/jwt-secrets
The app mints HS256 JWTs for any username (always with admin: False) and has a
separate endpoint that decodes a submitted token. If the decoded token contains
admin: true, the server returns the flag. The goal is to forge such a token.
Analysis
The provided source:
python read-only • copy allowedimport jwt # note this is the PyJWT module, not python-jwt SECRET_KEY = ? # TODO: PyJWT readme key, change later FLAG = ? @chal.route('/jwt-secrets/authorise/<token>/') def authorise(token): try: decoded = jwt.decode(token, SECRET_KEY, algorithms=['HS256']) except Exception as e: return {"error": str(e)} if "admin" in decoded and decoded["admin"]: return {"response": f"Welcome admin, here is your flag: {FLAG}"} elif "username" in decoded: return {"response": f"Welcome {decoded['username']}"} else: return {"error": "There is something wrong with your session, goodbye"} @chal.route('/jwt-secrets/create_session/<username>/') def create_session(username): encoded = jwt.encode({'username': username, 'admin': False}, SECRET_KEY, algorithm='HS256') return {"session": encoded}
Key observations:
- The token is signed and verified with HS256, a symmetric HMAC-SHA256 scheme.
The same
SECRET_KEYis used to both sign (increate_session) and verify (inauthorise). Whoever knows the secret can mint arbitrary valid tokens. create_sessionhardcodesadmin: False, so the legitimate flow can never setadmin: true. We must forge a token ourselves.- The decisive hint is the comment
# TODO: PyJWT readme key, change later. The PyJWT library's README uses the literal example secretsecretin its encode/decode snippet. The developer copied that and never changed it.
So the vulnerability is a weak/default HS256 secret key (secret), enabling
full token forgery and privilege escalation to admin.
Solution
- Read the source on the challenge page; note the PyJWT-readme comment pointing
at the default example secret
secret. - Forge an admin token signed with HS256 and key
secret. - Submit it to the
authoriseendpoint.
python read-only • copy allowed#!/usr/bin/env python3 import jwt import requests # The HS256 secret is the PyJWT README example key, never changed. SECRET = "secret" # Forge a token with admin:true (create_session would force admin:false). token = jwt.encode({"username": "admin", "admin": True}, SECRET, algorithm="HS256") print("forged token:", token) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. # eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9. # Mozu0MUZmsKUz3aAqi6REcuPETl4CncofpoBDqtDh-c r = requests.get(f"https://web.cryptohack.org/jwt-secrets/authorise/{token}/") print(r.json()) # {"response":"Welcome admin, here is your flag: crypto{REDACTED}"}
Or with curl:
curl -s "https://web.cryptohack.org/jwt-secrets/authorise/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.Mozu0MUZmsKUz3aAqi6REcuPETl4CncofpoBDqtDh-c/"
Response:
{"response":"Welcome admin, here is your flag: crypto{REDACTED}"}
Forged token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.Mozu0MUZmsKUz3aAqi6REcuPETl4CncofpoBDqtDh-c
Lesson / Mitigation
Never use library example/default secrets in production. With symmetric HS256, a
leaked or guessable secret allows complete token forgery — including elevating
admin to true. Use strong, random secrets, or prefer asymmetric RS256 so the
public verifying key can be distributed while the private signing key stays
protected.