Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-54902

CVE-2026-54902: Oj Ruby Gem Use-After-Free Vulnerability

CVE-2026-54902 is a use-after-free vulnerability in Oj (Optimized JSON) Ruby gem that can cause segmentation faults in SAJ mode. This post covers technical details, affected versions, impact, and mitigation steps.

Published:

CVE-2026-54902 Overview

CVE-2026-54902 is a Use-After-Free vulnerability [CWE-416] in Oj (Optimized JSON), a JSON parser and Object marshaller distributed as a Ruby gem. The flaw affects versions prior to 3.17.2 when the parser operates in Simple API for JSON (SAJ) mode. Oj::Parser does not protect cached object keys of 35 bytes or larger from Ruby garbage collection. A Ruby callback that triggers garbage collection inside hash_end can free the key string while the C parser still holds a pointer to it. Accessing the freed VALUE produces a segmentation fault, with an RIP pointing to 0x4242, indicating attacker-influenced control over freed memory contents. Version 3.17.2 remediates the issue.

Critical Impact

Attackers who can influence JSON input processed by Oj's SAJ mode can trigger a segmentation fault and potentially control freed memory contents, leading to denial of service or memory corruption.

Affected Products

  • Oj (Optimized JSON) Ruby gem versions prior to 3.17.2
  • Ruby applications using Oj::Parser in SAJ mode
  • Applications parsing untrusted JSON with hash keys of 35 bytes or larger

Discovery Timeline

  • 2026-07-01 - CVE-2026-54902 published to NVD
  • 2026-07-01 - Last updated in NVD database

Technical Details for CVE-2026-54902

Vulnerability Analysis

The vulnerability resides in Oj::Parser when running in SAJ (Simple API for JSON) mode. SAJ mode delivers streaming parse events to Ruby callbacks as the C parser walks the JSON document. Oj caches object keys to reduce allocation overhead. For keys of 35 bytes or larger, the parser stores a Ruby VALUE reference to the key string in its internal cache but does not mark the cached string as reachable during garbage collection.

When a user-supplied Ruby callback executes during hash_end, that callback can trigger a garbage collection cycle. Because the cached key is not rooted, Ruby's garbage collector reclaims the string. The C parser subsequently dereferences the stale VALUE pointer, producing memory corruption. A confirmed proof-of-concept shows the instruction pointer landing at 0x4242, a canary pattern that demonstrates the freed slot's contents can be shaped by an attacker.

Root Cause

The root cause is missing garbage collection protection for cached keys inside Oj::Parser. The C extension retains raw VALUE handles for keys exceeding 35 bytes without registering them with Ruby's mark-and-sweep collector. Any GC cycle that fires between key caching and key use invalidates the pointer.

Attack Vector

Exploitation requires an attacker to supply JSON input processed by an application using Oj in SAJ mode with a Ruby callback that can cause allocation or explicit GC during hash_end. The JSON payload must include hash keys of at least 35 bytes. Network delivery is feasible when web applications parse untrusted request bodies with Oj. The result is process termination through segfault, with a plausible path to controlled memory access when attackers can influence heap layout.

No verified exploit code is publicly available. See the GitHub Security Advisory GHSA-m578-w5vf-rfcm for maintainer details.

Detection Methods for CVE-2026-54902

Indicators of Compromise

  • Ruby process crashes with SIGSEGV when parsing JSON, especially with an instruction pointer at or near 0x4242.
  • Core dumps or crash reports referencing Oj SAJ callbacks such as hash_end in the stack trace.
  • Unexpected termination of Ruby workers handling JSON payloads containing long hash keys.

Detection Strategies

  • Inventory Ruby applications and Bundler lockfiles to identify Oj versions below 3.17.2.
  • Search source code for Oj::Parser usage combined with SAJ handlers that allocate objects or invoke GC.start inside hash_end.
  • Monitor application logs for repeated segfaults correlated with JSON parsing endpoints.

Monitoring Recommendations

  • Alert on Ruby worker restarts and abnormal exit codes on services that accept JSON input.
  • Capture core dumps in staging to inspect Oj-related crash signatures before production impact.
  • Track dependency updates through software composition analysis to flag vulnerable Oj versions in CI/CD pipelines.

How to Mitigate CVE-2026-54902

Immediate Actions Required

  • Upgrade the oj gem to version 3.17.2 or later across all Ruby applications and container images.
  • Rebuild and redeploy artifacts that bundle Oj as a transitive dependency, then verify with bundle list | grep oj.
  • Audit custom SAJ handlers to confirm no callback performs allocation or forced GC inside hash_end until the upgrade is complete.

Patch Information

The maintainer fixed the issue in Oj version 3.17.2 by protecting cached object keys from premature garbage collection. Reference the GitHub Security Advisory GHSA-m578-w5vf-rfcm for the patch commit and release notes.

Workarounds

  • Switch parsing away from Oj::Parser SAJ mode to Oj's default or strict modes until the gem is upgraded.
  • Reject or truncate JSON inputs containing hash keys of 35 bytes or larger at an upstream validation layer.
  • Remove explicit GC.start calls and heavy allocations from SAJ callbacks, especially hash_end handlers.
bash
# Update Oj to the patched release
bundle update oj --conservative
bundle list | grep '^  \* oj '
# Expected: oj (3.17.2) or later

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.