Critical JWE Ruby Flaw (CVE-2025-54887): How an AES-GCM Tag Check Bug Exposed Encrypted Data By CyberDudeBivash — precision threat intel for builders and defenders.

Executive summary

A critical bug in the Ruby jwe gem (JSON Web Encryption) allows attackers to bypass AES-GCM authentication and tamper with or decrypt JWE tokens. The issue stems from missing validation of the authentication tag; attackers can brute-force or truncate the tag, enabling forged ciphertexts and even recovery of the GCM GHASH subkey under some conditions. Impacted versions: ≤ 1.1.0. Fixed in 1.1.1Key rotation is required because the GHASH key may have leaked. CVSS v3.1: 9.1 (Critical)GitHubNVD


What exactly broke?

AES-GCM provides both confidentiality and integrity: decryption must verify a 128-bit authentication tag before releasing plaintext. The JWE spec mandates a 128-bit tag for A128GCM/A192GCM/A256GCM. The vulnerable Ruby implementation failed to enforce the tag length/validation correctly, letting attackers submit shortened tags that are feasible to brute-force. IETF DatatrackerGitHub

Practical effects confirmed by the advisory:

  • Modify a JWE to decrypt to an attacker-chosen value (integrity break).
  • Decrypt a JWE by observing parsing differences (oracle-style confidentiality loss).
  • Recover the GCM internal GHASH key, enabling broader forgery with the same key. GitHub

Why rotate keys if you never used GCM? The CNA/NVD notes that users are affected even if they don’t currently use AES-GCM, because the GHASH key may already have leaked; rotate the underlying encryption keys after upgrading. NVD


A quick refresher: JWE + AES-GCM

A compact JWE is:
BASE64URL(header).BASE64URL(iv).BASE64URL(ciphertext).BASE64URL(tag)

For AES-GCM in JWE:

  • IV size: 96 bits (12 bytes) — required.
  • Tag size: 128 bits (16 bytes) — required.
    Not meeting these invariants must be rejected. IETF Datatracker

Attack paths (defender’s view)

  1. Tag truncation + brute force
    If the library accepts tags <16 bytes, an attacker crafts ciphertexts and iterates over the reduced tag space until decryption “succeeds” — turning GCM’s strong integrity into a guessable check. (This is precisely what the fix closes by enforcing tag length.) GitHub
  2. Parsing-difference oracle
    With partial tag bypass, adversaries can distinguish parser errors vs. downstream decoding errors, leaking information and eventually recovering plaintext. GitHub
  3. GHASH subkey recovery
    Given sufficient chosen inputs and acceptance of malformed tags, an adversary can derive H = AES_K(0^128) (the GHASH key), enabling counterfeit tags for additional messages under that key. Result: broad token forgery risk. GitHubNVD

Impacted surface

  • Ruby apps that use the jwe gem for: encrypted JWTs, session cookies, SSO assertions, service-to-service tokens, or field-level data protection.
  • Any upstream gateway/service that trusts these JWEs for authZ or data integrity. (This can cascade into privilege escalation if tokens are accepted as valid.) GitHub

Detection & hunting

Quick content checks at the edge

  • Reject JWEs with enc in {A128GCM,A192GCM,A256GCM} and a tag length ≠ 16 bytes after Base64URL decode. This aligns with RFC 7518. IETF Datatracker

Telemetry clues

  • Spikes in JWE decryption failures around early August 2025 (probing/exploitation).
  • Tokens repeatedly failing policy checks but passing app-level parsing — look for inconsistent error sources.

Log analysis heuristic

  • For APIs that log decode stages, alert on “decryption success” + “schema/JSON error” combos, a sign of attacker-crafted plaintext designed to traverse parsing layers.

Remediation (do this now)

  1. Patch: Upgrade jwe to 1.1.1 (adds mandatory tag length check).rubyCopyEdit# Gemfile gem "jwe", "~> 1.1.1" # then bundle update jwe GitHub
  2. Rotate keys immediately: Assume the GHASH key (and thus integrity of messages under that key) may be compromised. Generate new symmetric keys, publish a new kid, and invalidate old tokens aggressively. NVD
  3. Force re-authentication for user sessions that relied on JWE. (Don’t trust long-lived tokens minted before the fix+rotation.)
  4. Gateway enforcement: At your API gateway/WAF, enforce tag.length == 16 for all GCM-JWEs; drop on mismatch. (This mirrors the RFC requirement.) IETF Datatracker
  5. SBOM & CI: Add bundler-audit (or equivalent) to CI, failing builds on CVE-2025-54887 for versions ≤ 1.1.0. Track runtime gems via SBOM and verify production parity with CI.

Validation after the fix

  • Unit tests: Attempt to decrypt a JWE with a 1-byte tag; expect failure.
  • Interoperability: Cross-decrypt with another JOSE library (e.g., Nimbus JOSE) that always uses 128-bit tags to confirm behavior matches spec. GitHubjavadoc.io

Governance notes for security leaders

  • Risk: Critical (remote, no auth, data integrity + confidentiality at stake). Confirmed by CNA/NVD with CVSS 9.1GitHub
  • SLA: 24–48h to patch+rotate for external-facing systems.
  • Attestation: Record evidence of rotation (new kid, cutoff time) and purge of pre-fix tokens.
  • Policy: Require spec-level invariants (e.g., AES-GCM 128-bit tags) as gateway checks, not just library defaults.

References

  • GitHub Advisory (GHSA-c7p4-hx26-pr73) — root cause, impact, fix 1.1.1, rotate keys. GitHub
  • NVD CVE-2025-54887 — CNA summary, CVSS 9.1, key-rotation guidance. NVD
  • RubySec — ecosystem advisory reiterating tag-length fix and rotation. RubySec
  • Tenable — vendor summary of attack consequences. Tenable®
  • RFC 7518 (JWA) — JWE must use a 128-bit tag for AES-GCM. IETF Datatracker

Leave a comment

Design a site like this with WordPress.com
Get started