GHSA-c32j-vqhx-rx3x

Suggest an improvement
Source
https://github.com/advisories/GHSA-c32j-vqhx-rx3x
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-c32j-vqhx-rx3x/GHSA-c32j-vqhx-rx3x.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-c32j-vqhx-rx3x
Aliases
  • CVE-2026-45363
Downstream
Related
Published
2026-05-18T17:24:55Z
Modified
2026-05-26T01:59:14.900152468Z
Severity
  • 7.4 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N CVSS Calculator
Summary
ruby-jwt: Empty-key HMAC bypass; cross-language sibling of CVE-2026-44351
Details

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 keyfinder: argument returns "", nil, or an array containing nil for an unknown key. JWT::Decode#findkey 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:)

Database specific
{
    "github_reviewed": true,
    "cwe_ids": [
        "CWE-1391",
        "CWE-287",
        "CWE-326"
    ],
    "github_reviewed_at": "2026-05-18T17:24:55Z",
    "nvd_published_at": null,
    "severity": "HIGH"
}
References

Affected packages

RubyGems / jwt

Package

Name
jwt
Purl
pkg:gem/jwt

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
3.2.0

Affected versions

0.*
0.1.1
0.1.2
0.1.3
0.1.4
0.1.5
0.1.6
0.1.7
0.1.8
0.1.10
0.1.11
0.1.13
1.*
1.0.0
1.2.0
1.2.1
1.3.0
1.4.0
1.4.1
1.5.0
1.5.1
1.5.2
1.5.4
1.5.5
1.5.6
2.*
2.0.0.beta1
2.0.0
2.1.0
2.2.0.pre.beta.0
2.2.0
2.2.1
2.2.2
2.2.3
2.3.0
2.4.0.beta1
2.4.0
2.4.1
2.5.0
2.6.0
2.7.0
2.7.1
2.8.0
2.8.1
2.8.2
2.9.0
2.9.1
2.9.2
2.9.3
2.10.0
2.10.1
2.10.2
3.*
3.0.0.beta1
3.0.0
3.1.0
3.1.1
3.1.2

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-c32j-vqhx-rx3x/GHSA-c32j-vqhx-rx3x.json"