Fix algorithm confusion that allows JWT forgery via RSA JWK as HMAC key
GHSA-q843-6q5f-w55g: an RSA JWK without an "alg" parameter was accepted
as the verification key for HS256/384/512 tokens. Because the jwk_item_t
union shares storage between provider_data (RSA EVP_PKEY *) and
oct.{key,len} (HMAC bytes/length), the OpenSSL HMAC path read a
zero-length key and produced a successful verification for any token
signed as HMAC("", header.payload). This let an attacker forge tokens
using only the public JWKS.
Bind algorithm acceptance to the JWK's actual "kty" rather than its
optional "alg" hint, in three layered places:
* jwt-private.h: new jwt_alg_required_kty() helper providing the
authoritative JWA-algorithm to JWK-kty mapping.
* jwt-common.c: __setkey_check() now rejects any setkey() / verify
callback that pairs a non-none algorithm with an incompatible kty.
This is the primary fix and runs at both setkey and post-callback.
* jwt-verify.c: __verify_config_post() re-checks kty once jwt->alg is
bound from the token, blocking malformed JWKs whose own alg hint
disagrees with their kty.
* jwt.c: __check_hmac() defensive backstop in the single chokepoint
used by all three crypto backends; refuses any non-oct key for HMAC.
Tests added in jwt_security.c cover the original PoC, the realistic
JWKS callback exploit pattern, all three HS sizes, RSA/EC/OKP keys
mis-targeted at HS256, and the malformed-JWK defensive verify path.
A few existing tests (hs256_token_failed, verify_es256_bad_sig,
sign_es256_bad_sig, rsa_ec_short) were updated; they previously
documented the vulnerable behavior under the guise of "different ways"
of failing and now assert the correct earlier rejection.
Signed-off-by: Ben Collins <bcollins@libjwt.io>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
[!WARNING] Version 3 of LibJWT is a complete overhaul of the code. Please see documentation for usage.
| Standard | RFC | Description |
|---|---|---|
JWS | :page_facing_up: RFC-7515 | JSON Web Signature |
JWE | :page_facing_up: RFC-7516 | JSON Web Encryption |
JWK | :page_facing_up: RFC-7517 | JSON Web Keys and Sets |
JWA | :page_facing_up: RFC-7518 | JSON Web Algorithms |
JWT | :page_facing_up: RFC-7519 | JSON Web Token |
[!NOTE] Throughout this documentation you will see links such as the ones above to RFC documents. These are relevant to that particular part of the library and are helpful to understand some of the specific standards that shaped the development of LibJWT.
[!NOTE] OpenSSL is required and used for JWK(S) operations.
JWS Algorithm alg | OpenSSL | GnuTLS | MbedTLS |
|---|---|---|---|
HS256 HS384 HS512 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
ES256 ES384 ES512 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
RS256 RS384 RS512 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
EdDSA using ED25519 | :white_check_mark: | :white_check_mark: | :x: |
EdDSA using ED448 | :white_check_mark: | :white_check_mark: >= 3.8.8 | :x: |
PS256 PS384 PS512 | :white_check_mark: | :white_check_mark: | :white_check_mark:* |
ES256K | :white_check_mark: | :x: | :white_check_mark: |
* RSASSA-PSS support in MbedTLS depends on Mbed-TLS/TF-PSA-Crypto#154
:link: Current Docs
:link: Legacy Docs v2.1.1
:link: GitHub Repo
LibJWT is available in most Linux distributions as well as through Homebrew for Linux, macOS, and Windows.
$ mkdir build $ cd build $ cmake .. $ make