Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
💎
💎 RubyGems
Not in CISA KEV
CRITICAL severity

CVE-2026-45363 — jwt

CRITICALFix: jwt/ruby-jwt@9820020

CVE-2026-45363 is a critical-severity (CVSS 9.1) Improper Authentication vulnerability in jwt. A fix is available for jwt — see the affected versions and patch details below.

`jwt` (Ruby gem) - empty-key HMAC bypass

Also known asGHSA-c32j-vqhx-rx3x
Published
Jul 14, 2026
Updated
Sep 20, 2026
Affected
2 pkgs
Patched
2 / 2
Exploits
None indexed
Exploitation data as of Sep 29, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

No confirmed exploitation observed yet

  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
  • A successful exploit gives an attacker total control of the affected component, not partial access.
  • CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-45363.

EPSS Exploitation Probability

via FIRST.org ↗
0.4%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs28th percentile — riskier than 28% of all scored CVEsHighest risk

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

CVE-2026-45363 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.

Where this sits among everything scored

Of 380,526 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.

Real-World Exposure

2 pkgs affected
💎jwt💎jwt

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects RubyGems packages — download data is not available via public APIs for these ecosystems.

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:)

Affected Packages

2 total 2 fixed
EcosystemPackageVulnerable rangeFix
💎RubyGemsjwt≥ 3.0.0&&< 3.2.03.2.0bundle update jwt --conservative
💎RubyGemsjwtall versions2.10.3bundle update jwt --conservative

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for jwt, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update jwt to 3.2.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-45363 is resolved across your whole dependency graph.

  3. Workarounds

    Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatImportant
ProductFixed inAdvisory
Red Hat Satellite 6.16 for RHEL 8rubygem-jwt-0:2.10.3-1.el8satRHSA-2026:63327
Red Hat Satellite 6.17 for RHEL 9ansible-core-1:2.16.19-1.el9satRHSA-2026:63387
Red Hat Satellite 6.18 for RHEL 9pulpcore-obsolete-packages-0:1.3.1-5.el9pcRHSA-2026:63386
Red Hat Satellite 6.19 for RHEL 9rubygem-jwt-0:2.10.3-1.el9satRHSA-2026:63385

Frequently Asked Questions

`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
O3 Security · Impact-Aware SCA

Is CVE-2026-45363 in your dependencies?

Find it across RubyGems, including transitive dependencies.

CVE-2026-45363: jwt (Critical 9.1) | O3 Security