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

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

CVE-2026-54898 is a heap use-after-free vulnerability in Oj (Optimized JSON) Ruby gem that occurs when SAJ/SAJ2 callbacks mutate the input JSON string. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-54898 Overview

CVE-2026-54898 is a heap use-after-free vulnerability [CWE-416] in Oj (Optimized JSON), a JSON parser and Object marshaller distributed as a Ruby gem. The flaw affects Oj::Parser#parse in all versions prior to 3.17.2. During SAJ or SAJ2 streaming callbacks, the C engine retains a raw const byte * pointer into the Ruby string's internal buffer. If a callback such as hash_start mutates the input by calling String#replace with a longer value, Ruby reallocates the buffer and frees the original allocation. The parser then reads freed memory at parser.c:607. Maintainers resolved the issue in Oj version 3.17.2.

Critical Impact

Callback-triggered mutation of the input JSON string leads to reads from freed heap memory, causing crashes or undefined parser behavior in local Ruby processes.

Affected Products

  • Oj (Optimized JSON) Ruby gem, versions prior to 3.17.2
  • Ruby applications using Oj::Parser#parse with SAJ or SAJ2 callback handlers
  • Applications where callback handlers may mutate the parsed input string

Discovery Timeline

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

Technical Details for CVE-2026-54898

Vulnerability Analysis

Oj exposes a streaming API (SAJ and SAJ2) that invokes Ruby callbacks as JSON tokens are parsed. The C parser scans the input by holding a direct pointer into the underlying Ruby string's byte buffer. This design assumes the buffer remains stable for the duration of parsing. When a callback executes arbitrary Ruby code, it can invalidate that assumption by replacing the string contents. The next byte read at parser.c:607 dereferences a dangling pointer, resulting in a heap use-after-free condition. Consequences range from process crashes to memory corruption, depending on allocator state and the size of the replacement string.

Root Cause

The root cause is a lifetime mismatch between the C engine's cached buffer pointer and the Ruby string it references. Ruby's String#replace with a longer value forces reallocation and frees the original heap block. The parser does not refresh its pointer after control returns from the callback. This violates the invariant that the scanned buffer remains live throughout parsing.

Attack Vector

Exploitation requires the attacker to influence a SAJ or SAJ2 callback so that it mutates the input string during parsing. This is a local vector: an application must supply attacker-controlled callback logic or route untrusted data through a handler that resizes the source string. Triggering the condition typically produces a crash. Reliable code execution would require additional heap-shaping primitives and is not described in the advisory.

No verified exploit code is available. See the GitHub Security Advisory GHSA-q2gm-54r6-8fwm for maintainer notes.

Detection Methods for CVE-2026-54898

Indicators of Compromise

  • Unexpected segmentation faults or SIGSEGV in Ruby processes calling Oj::Parser#parse
  • Ruby crash logs referencing parser.c line 607 or Oj internal frames
  • ASAN or Valgrind reports flagging heap-use-after-free within the Oj native extension

Detection Strategies

  • Inventory Ruby applications and enumerate installed Oj gem versions using bundle list or gem list oj
  • Audit SAJ and SAJ2 handler implementations for any code path that calls String#replace, <<, or concat on the parsed input
  • Run integration tests under AddressSanitizer against parsers that consume untrusted JSON

Monitoring Recommendations

  • Alert on abnormal Ruby worker restarts or crash-loop patterns in application servers using Oj
  • Collect and centralize core dumps to identify recurring stack traces inside the Oj native extension
  • Track dependency drift so that gem upgrades to Oj 3.17.2 or later are enforced across environments

How to Mitigate CVE-2026-54898

Immediate Actions Required

  • Upgrade the Oj gem to version 3.17.2 or later in all Ruby applications
  • Rebuild and redeploy container images and application bundles that ship the vulnerable gem
  • Review custom SAJ and SAJ2 callback classes to remove mutations of the input string

Patch Information

The maintainers fixed CVE-2026-54898 in Oj version 3.17.2. Update the gem via bundle update oj or by pinning gem 'oj', '>= 3.17.2' in the Gemfile. Details are provided in the GitHub Security Advisory GHSA-q2gm-54r6-8fwm.

Workarounds

  • Refactor SAJ and SAJ2 callback handlers so they never resize or replace the input JSON string
  • Copy required substrings out of the parser input before performing any mutation elsewhere
  • Route untrusted JSON through non-streaming Oj modes until the upgrade is complete
bash
# Configuration example: pin the patched Oj version
bundle update oj
gem list oj
# Ensure output shows: 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.