The key ID parameter
The kid (Key ID) header parameter is defined in RFC 7517 §4.5 as an optional hint identifying which key the issuer used to sign the token. It allows a server that manages multiple keys (e.g., for key rotation) to look up the correct verification key without trying each one.
The specification is deliberately vague about the format: "The structure of the kid value is unspecified." In practice, implementations resolve it against a filesystem path, a database row, an in-memory keystore, or even a URL - and when this resolution is performed with attacker-supplied input without sanitization, the consequences range from authentication bypass to server-side code execution.
Path traversal variant
When the server resolves kid as a filesystem path to load the signing key, path traversal sequences allow the attacker to substitute any readable file on the server as the "key." Two particularly useful targets are:
/dev/null(Linux) - reads as an empty string; sign with an empty HMAC secret/proc/self/cmdline- process command line; predictable on known environments- Any world-readable static file with known content - sign with that file's bytes as the HMAC secret
Windows path traversal
On Windows servers, the equivalent technique uses Windows path separators and targets files like NUL (equivalent to /dev/null) or C:\Windows\win.ini (known content, readable by all users):
SQL injection variant
When the server queries a database for the key using the kid value, SQL injection allows the attacker to make the query return an arbitrary value - one they control. By injecting a UNION SELECT, they can make the key lookup return any string, then sign the forged token with that same string as the HMAC secret.
; DROP TABLE keys--) or out-of-band channels (DNS lookups via load_file() in MySQL) may also be possible. The kid SQLi surface is often unmonitored since it is not a typical API endpoint.SSRF via URL-type kid
Some implementations accept a full URL in the kid field and fetch the key from it - treating kid as a JKU-equivalent. This creates an SSRF vector:
The empty string / null byte trick
When path traversal to /dev/null is not directly possible but the key lookup returns an empty value for a non-existent kid, some libraries will verify the signature against an empty key. Sign the forged token with an empty HMAC secret:
- Path traversal via
kidreported on multiple HackerOne programs targeting API gateway products and identity middleware - SQLi via
kiddemonstrated in PortSwigger's lab and confirmed in real enterprise middleware deployments - SSRF via URL-type
kidchained to internal metadata service access (IMDS) in cloud environments - Critical severity ratings common when combined with
role=adminclaim forgery
Mitigations
- Validate
kidagainst an allowlist of known key identifiers - reject anything not in the list - Never use
kidas a direct database query parameter without parameterised queries - Never resolve
kidas a filesystem path; use it only as a map key into a pre-loaded in-memory keystore - Reject
kidvalues containing path separators, SQL metacharacters, or URL schemes - If URL-type
kidis required, enforce a strict allowlist of trusted domains