Varol Cagdas Tok

Personal notes and articles.

JWT Vulnerabilities

Every JWT vulnerability documented so far shares one root: the server derives trust from a field inside the token rather than from configuration it controls. The token is the attacker's input. Fields inside it should inform the server how to validate the token only when the server enforces strict constraints on what values those fields may contain.


The alg:none Attack

RFC 7519 defines none as a valid algorithm value, intended for cases where the token integrity is guaranteed by other means. Libraries that implement this allow tokens with "alg": "none" to be accepted without any signature. The signature section is empty.

An attacker with a valid token modifies the payload (changing role from user to admin, for example), sets the header algorithm to none, and removes the signature. A vulnerable library accepts this token because it performs signature verification only when an algorithm requiring it is specified, and none requires no verification.

The fix is an allowlist of acceptable algorithms configured by the application, not read from the token. The library must reject any token whose alg field is not on that list before attempting verification.


RS256 to HS256 Confusion

RS256 uses an RSA key pair: tokens are signed with the private key and verified with the public key. HS256 uses a single shared secret for both signing and verification. The public key in an RS256 deployment is often exposed, either intentionally (JWKS endpoint) or through disclosure.

A library that reads the algorithm from the token header and selects the verification function accordingly can be exploited as follows: an attacker modifies the header to specify HS256 instead of RS256, then signs the token using the server's public RSA key as the HMAC secret. The server reads HS256 from the header, retrieves what it believes is the HMAC secret (which is, in vulnerable implementations, the configured public key), and verifies the HMAC. Since the attacker signed with that same public key, verification passes.

The fix is identical to the alg:none case: the application specifies which algorithm to use; the token's declared algorithm is compared against that specification and rejected if it does not match.


Weak HMAC Secrets

HS256 tokens can be brute-forced offline. The attacker needs only a valid token. They iterate candidate secrets, recompute the HMAC over the token's header and payload, and compare against the token's signature. If the secret is short, a dictionary word, or a default value left from development, it can be recovered in minutes using tools like hashcat with JWT-specific rulesets.

HMAC secrets for JWT signing must be at least 256 bits of cryptographically random data. A human-readable string of any length is a poor secret because it occupies a small fraction of the keyspace for its byte length.


kid and jku Injection

The kid (key ID) header parameter identifies which key was used to sign the token. Some implementations use the kid value to perform a database lookup or filesystem read to retrieve the corresponding key. If the kid value is used in a SQL query without parameterization, it is a SQL injection point inside JWT validation. If it is used as a filename, it is a path traversal point.

The jku (JWK Set URL) and x5u parameters instruct the server to fetch the verification key from a URL. An implementation that fetches from an attacker-controlled URL is equivalent to accepting attacker-controlled keys. The server must validate that any key URL matches a preconfigured allowlist of trusted endpoints before fetching from it.