Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type JWT Attacks
Difficulty Practitioner
Objective Exploit path traversal in the kid header to force the server to use /dev/null as its signing key, forge a valid JWT as administrator, and delete carlos

JWT Authentication Bypass via kid Header Path Traversal

I logged in as wiener:peter and decoded the session JWT:

Screenshot

Header:

{
    "kid": "37addb45-68d5-4184-912e-b7390db333a4",
    "alg": "HS256"
}

Two things stand out: alg: HS256 — symmetric, a single shared secret — and kid looks like a UUID that probably maps to a key file on the filesystem. No jwk/jku support, no weak secret to brute-force. The attack surface is the kid parameter itself.

When the server constructs a file path from kid without sanitizing path traversal sequences, we can make it read an arbitrary file instead of the intended key. The target is /dev/null — it exists on every Linux system, is world-readable, and always returns an empty byte string. If kid points there, the server reads empty as the HMAC key. We sign the forged JWT with that same empty key, and the verification matches.

I created a symmetric key in Burp's JWT Editor using AA== (the base64 encoding of a null byte — as close to "empty" as JWK format allows):

echo -ne '\0' | base64
# AA==
{
    "kty": "oct",
    "kid": "99e56963-1a89-4a3b-9845-9f0c80f01ad4",
    "k": "AA=="
}
Screenshot

I modified the JWT header to traverse to /dev/null and changed sub to administrator:

Header:

{
    "kid": "../../../../../../../../dev/null",
    "alg": "HS256"
}

The ../../../../../../../../ sequence walks up past whatever directory the server starts from to reach the filesystem root, then descends into /dev/null. The count doesn't need to be exact — once traversal hits the root, extra ../ segments are a no-op. Using eight or more guarantees escape from any reasonable directory depth.

I signed the token with our null-byte symmetric key:

Screenshot

Pasted into the browser's session cookie storage:

Screenshot

Admin panel appeared. kid is a user-controlled string that shouldn't be used as a filesystem path without stripping ../ sequences — any file readable by the web server process is reachable, not just /dev/null. Deleted carlos:

Screenshot

Lab solved

Resources