diff --git a/gems/jwt/CVE-2026-45363.yml b/gems/jwt/CVE-2026-45363.yml new file mode 100644 index 0000000000..b8c96d713b --- /dev/null +++ b/gems/jwt/CVE-2026-45363.yml @@ -0,0 +1,58 @@ +--- +gem: jwt +cve: 2026-45363 +notes: 'CVE has been reserved, but not filled in.' +ghsa: c32j-vqhx-rx3x +url: https://github.com/jwt/ruby-jwt/security/advisories/GHSA-c32j-vqhx-rx3x +title: 'ruby-jwt: Empty-key HMAC bypass; cross-language sibling of CVE-2026-44351' +date: 2026-05-18 +description: | + `JWT.decode(token, '', true, algorithm: 'HS256')` accepts an + attacker-forged token. `OpenSSL::HMAC.digest('SHA256', '', payload)` + returns a valid digest under an empty key, and no + `raise InvalidKeyError if key.empty?` precondition exists in the HMAC + algorithm. + + ``` + JWT.decode(token, "", true, algorithm: 'HS256') + -> JWA::Hmac.verify(verification_key: "", ...) + -> OpenSSL::HMAC.digest('SHA256', "", signing_input) == signature + ``` + + The same path is reached when a keyfinder block or key_finder: argument + returns "", nil, or an array containing nil for an unknown key. + JWT::Decode#find_key only rejects literal nil and empty arrays, and + JWT::JWA::Hmac silently coerces nil to "" (signing_key ||= '') before + signing. + + ``` + JWT.decode(token, nil, true, algorithms: ['HS256']) { |_h| "" } + -> find_key returns "" # "" && !Array("").empty? == true + -> JWA::Hmac.verify(verification_key: "", ...) + -> verifies + ``` + + Common application patterns that produce the unsafe value: + `redis.get("kid:#{kid}").to_s`, ORM string columns with `default: ''`, + `ENV['SECRET'] || ''`, `Hash.new('')` lookups, `[primary, fallback]` + where fallback may be nil. Applications passing a non-empty static + `key:`, or whose keyfinder returns nil / raises on miss, are not + affected. + + The existing `enforce_hmac_key_length` option would block this but + defaults to false. On OpenSSL ≥ 3.5 the empty-key HMAC.digest call no + longer raises, so the OpenSSL-3.0 rescue in JWA::Hmac#sign does not + fire. + + Affects HS256/HS384/HS512 via both JWT.decode (positional key and block + keyfinder) and `JWT::EncodedToken#verify_signature!(key_finder:)`. +cvss_v3: 7.4 +patched_versions: + - ">= 3.2.0" +related: + url: + - https://github.com/jwt/ruby-jwt/security/advisories/GHSA-c32j-vqhx-rx3x + - https://github.com/jwt/ruby-jwt/commit/db560b769a07bd9724e77ff505011ac01872106f + - https://github.com/jwt/ruby-jwt/releases/tag/v3.2.0 + - https://github.com/advisories/GHSA-c32j-vqhx-rx3x + - https://www.cve.org/CVERecord?id=CVE-2026-45363