Aller au contenu

JWT KID Header Injection

Ce contenu n’est pas encore disponible dans votre langue.

SeverityHigh
ClassificationsCWE-345: Insufficient Verification of Data Authenticity
Attack Pattern
OWASP CategoryOWASP API2:2023 Broken Authentication

The kid (Key ID) JWT header field is intended to tell the server which key to use for signature verification. When this value is passed unsanitized to a database query or a file system lookup, attackers can inject a payload that causes the server to use an attacker-controlled key, effectively allowing them to forge arbitrary tokens.

JWTop tests four variants of this attack:

  • SQL Injection — injects a SQL payload into kid (e.g. ' UNION SELECT 'secret' ...) so that the database returns a known value as the key.
  • Path Traversal — sets kid to a filesystem path such as /dev/null so the server reads an empty file as the key, which can be matched with an empty HMAC secret.
  • Command Injection — sets kid to a shell metacharacter payload (e.g. ; id, $(id)) targeting servers that shell out using the kid value to locate a key file.
  • LDAP Injection — sets kid to an LDAP filter metacharacter payload (e.g. *)(uid=*) targeting servers that use the kid value in an LDAP lookup to resolve a signing key.

Here is a valid JWT signed with HS256:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

The attacker crafts a token with a kid header that injects into the key-lookup query and re-signs it with the value the query is made to return (secret):

{
"alg": "HS256",
"typ": "JWT",
"kid": "' UNION SELECT 'secret' FROM tokens WHERE '1'='1"
}

The attacker sets kid to /dev/null and re-signs the token with an empty HMAC secret. If the server reads the signing key from the path named by kid, it receives zero bytes:

{
"alg": "HS256",
"typ": "JWT",
"kid": "/dev/null"
}

The attacker sets kid to a shell metacharacter payload and re-signs the token with an empty HMAC secret. If the server shells out with the kid value to locate a key file (e.g. openssl ... -in keys/$kid.pem), the injected command runs on the server:

{
"alg": "HS256",
"typ": "JWT",
"kid": "; id"
}

The attacker sets kid to an LDAP filter metacharacter payload and re-signs the token with an empty HMAC secret. If the server interpolates the kid value into an LDAP search filter to resolve a signing key (e.g. (&(objectClass=key)(kid=$kid))), the injected filter term can make the lookup match an unintended entry:

{
"alg": "HS256",
"typ": "JWT",
"kid": "*)(uid=*))(|(uid=*"
}

If you want to test if your server is vulnerable to the “JWT KID Injection” vulnerability, you can use the crack command:

Terminal window
jwtop crack [token] --url [url]

The crack server probe currently covers the SQL Injection and Path Traversal variants only. Command Injection and LDAP Injection are exploit-only — generate the token below and test it against your server manually.

To generate a token with a kid injection payload, use the exploit kidinjection command:

Terminal window
jwtop exploit kidinjection [token] --mode sql

A successful KID injection attack allows an attacker to forge a JWT that the server accepts as legitimate. This can lead to full authentication bypass, privilege escalation, or impersonation of any user in the system.

  • Validate the kid value before using it — reject values containing SQL metacharacters, path separators, shell metacharacters, LDAP filter metacharacters, or characters outside a safe allowlist (e.g. alphanumeric and hyphens only).
  • Use parameterised queries when looking up keys by kid in a database to prevent SQL injection.
  • Never read key material from user-controlled file paths — store keys in a secure key store and use kid only as an opaque identifier mapped server-side to a known key.
  • Never pass kid to a shell command — if key lookup requires an external process, use an allowlist of key IDs and pass the resolved path as an argument, never build a shell string from kid.
  • Escape LDAP filter metacharacters in the kid value (or use a parameterised LDAP filter API) before it is interpolated into a search filter.
  • Hard-code or allowlist permitted kid values where possible.