๐Ÿ” JWT Tampering: From Token to Admin Takeover (with PinewoodStore Demo)

๐Ÿ‘‹ Welcome back to the blog!
Today weโ€™re diving into the world of JWT Tampering. Youโ€™ll see how an attacker can go from a basic user to full-blown admin by exploiting insecure JWT implementations. Weโ€™ll walk through how JWTs work, common vulnerabilities, and top it off with a real-world demo using our intentionally vulnerable app โ€” PinewoodStore.

Ready to hack some tokens? Letโ€™s go. ๐Ÿ˜ˆ


๐Ÿง  What is JWT Authentication?

JWT (JSON Web Token) is a compact, self-contained way to transmit information between parties securely. Itโ€™s often used for authentication in modern web applications and APIs.

Hereโ€™s what happens when a user logs in:

  1. Server verifies credentials โœ…
  2. Server generates a JWT signed with a secret/private key ๐Ÿงพ๐Ÿ”‘
  3. Server sends this JWT back to the client
  4. Client sends the JWT in every subsequent request using the Authorization header

๐Ÿงฑ Structure of a JWT

..

Each part is Base64URL-encoded and has a specific purpose:


1. Header

Purpose: Describes the token type and signing algorithm.
Format: Base64URL-encoded JSON.
Example Decoded:

{
  "alg": "HS256",  // Signing algorithm (e.g., HMAC-SHA256)
  "typ": "JWT"     // Token type
}

Key Fields:

  • alg: Algorithm used for the signature (HS256, RS256, ES256, etc.)
  • typ: Always "JWT" for standard tokens
  • kid (optional): Key ID โ€“ used for key rotation in systems with multiple signing keys

๐Ÿ” Security Note:

  • Header is not encrypted, only Base64URL-encoded.
  • Never accept tokens with alg: "none" โ€” that means no signature at all!

2. Payload (Claims)

Purpose: Contains user data and metadata (claims).
Format: Base64URL-encoded JSON.
Example Decoded:

{
  "sub": "user123",       // Subject (user ID)
  "iat": 1516239022,      // Issued-at timestamp
  "exp": 1516242622,      // Expiration timestamp
  "roles": ["admin"],     // Custom claim
  "name": "John Doe"      // Custom claim
}

๐Ÿ”– Standard Claims (from RFC 7519):

ClaimPurposeExample
subSubject (user ID)"sub": "user123"
iatIssued atUnix timestamp
expExpirationUnix timestamp
audAudience"aud": ["api.example.com"]
issIssuer"iss": "auth-server"

โœจ Custom Claims:

  • Used to store app-specific data, like roles, permissions, name, email, etc.
  • Do not store sensitive info (e.g., passwords) โ€” payload is not encrypted!

3. Signature

Purpose: Verifies the tokenโ€™s integrity and authenticity.

How Itโ€™s Created:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secretKey
)

Key Fields/Concepts:

  • Signing Algorithm: Depends on alg in the header (HS256, RS256, etc.)
  • Secret Key / Private Key: Used to sign the token
  • Signature: Final output of the algorithm; prevents tampering

โœ… If the header or payload is modified, the signature becomes invalid unless the attacker has the signing key.


๐Ÿ”‘ Bearer Token Usage

JWTs are typically included in the Authorization header when calling APIs:

GET /protected HTTP/1.1  
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

๐Ÿ›‘ Common JWT Vulnerabilities

Letโ€™s break down where things go wrong โ€” and how attackers take over accounts like a boss. ๐Ÿง ๐Ÿ’ฅ


1. ๐Ÿšซ alg: none Vulnerability

If the server doesnโ€™t enforce signature checks, an attacker can send an unsigned token:

{
  "alg": "none",
  "typ": "JWT"
}

๐Ÿ’ฅ Exploit:

curl -H "Authorization: Bearer " http://target.com/api

โœ… Fix: Always verify the signature and reject alg: none.


2. ๐Ÿ”„ Algorithm Confusion

If the server supports both RS256 (asymmetric) and HS256 (symmetric) without validationโ€ฆ

An attacker can forge an HS256 token using the public key as a secret.

jwt.encode({"sub": "admin"}, key=public_key, algorithm="HS256")

๐Ÿ”ฅ Boom! Youโ€™re admin.

โœ… Fix: Lock down supported algorithms and enforce strict verification.


3. ๐Ÿ•’ Ignored Expiration

If the exp field isnโ€™t checked, a token can be reused forever.

{
  "exp": 1600000000
}

๐Ÿงช Test:

curl -H "Authorization: Bearer " http://target.com/api

โœ… Fix: Always validate exp.


4. ๐Ÿ”“ No Signature Verification

This is what we exploited in PinewoodStore ๐Ÿ‘‡

Vulnerable Code:

private Map extractAllClaims(String token) {
    String[] parts = token.split("\\.");
    String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]));
    return objectMapper.readValue(payloadJson, Map.class);
}

๐Ÿ˜ฑ It just decodes the token without verifying the signature.

๐Ÿ‘ฟ Modify the payload to:

{
  "sub": "admin",
  "roles": ["admin"]
}

Then Base64 encode it and send it with the original header and signature. The server doesnโ€™t care โ€” youโ€™re now admin.


๐Ÿงช Real-World Demo: PinewoodStore

Hereโ€™s how we take over an account using JWT tampering in PinewoodStore:

๐Ÿงฉ Steps:

  1. Log in as a normal user โ†’ get a valid JWT
  2. Decode the payload: { "sub": "user", "roles": ["user"] }
  3. Modify to: { "sub": "admin", "roles": ["admin"] }
  4. Base64 encode and rebuild the token
  5. Send request with: Authorization: Bearer

๐Ÿ’ฅ Youโ€™re now in the admin panel!


๐Ÿ“Š JWT Testing Matrix

Test CaseShould Be Rejected?
1. alg: noneโœ… Yes
2. Expired tokenโœ… Yes
3. Tampered payloadโœ… Yes
4. Algorithm switchโœ… Yes
5. Missing signatureโœ… Yes

๐Ÿงช Tools to Help You Hack JWTs

  • ๐Ÿ”ง jwt_tool โ€“ Modify, sign, test tokens
  • ๐Ÿ” Burp Suite JWT Scanner Extension
  • ๐Ÿงช Postman for quick token tests
  • ๐Ÿ” jwt.io debugger

โœ… JWT Security Best Practices

  • ๐Ÿ”’ Always verify the signature
  • โŒ Never accept alg: none
  • ๐Ÿ“‰ Enforce token expiration
  • โ›” Donโ€™t put sensitive info in the payload
  • ๐Ÿ” Use strong secrets (for HS256)
  • ๐Ÿงพ Prefer short-lived access tokens and refresh tokens
  • โœ… Implement role-based access control on the server

๐Ÿง  Summary

JWTs are powerful, but power without control is dangerous.
As shown in PinewoodStore, skipping a simple signature check can lead to full account takeover.

So next time you build or audit a JWT-based app, ask:

๐Ÿค” โ€œWhat happens if someone tampers with this token?โ€

If the answer is โ€œNothingโ€, then youโ€™re doing it right. ๐Ÿ™Œ