CVE-2026-54899 Overview
CVE-2026-54899 is a heap use-after-free vulnerability in Oj (Optimized JSON), a JSON parser and object marshaller distributed as a Ruby gem. The flaw exists in versions prior to 3.17.2 and is triggered when the symbol_keys option is toggled from true to false on a reused Oj::Parser instance. The internal key cache is freed via cache_free without clearing the pointer, and the next parse call reads from the freed cache through cache_intern. Maintainers fixed the issue in version 3.17.2.
Critical Impact
Applications parsing untrusted JSON with a reused Oj::Parser instance can experience memory corruption, leading to crashes or potential information disclosure [CWE-416].
Affected Products
- Oj (Optimized JSON) Ruby gem versions prior to 3.17.2
- Ruby applications using Oj::Parser with dynamic symbol_keys toggling
- Downstream projects and services embedding vulnerable Oj releases
Discovery Timeline
- 2026-07-01 - CVE-2026-54899 published to NVD
- 2026-07-01 - Last updated in NVD database
Technical Details for CVE-2026-54899
Vulnerability Analysis
Oj provides high-performance JSON parsing for Ruby through the Oj::Parser class, which caches interned keys for reuse across parse operations. When symbol_keys is set to true, the parser maintains an internal cache of symbol keys to accelerate repeated deserialization. This cache is backed by heap-allocated memory managed by Oj's native C extension.
The root cause is a failure to nullify a dangling pointer after freeing the underlying cache. The vulnerability is classified as a use-after-free [CWE-416], a memory corruption class that commonly enables denial of service and, depending on heap layout, information disclosure or code execution.
Root Cause
When an application invokes the setter to disable symbol_keys on an existing Oj::Parser instance, the function opt_symbol_keys_set calls cache_free to release the key cache. The function does not reset the internal pointer to NULL or reinitialize the cache structure. On the subsequent call to parse JSON, cache_intern dereferences the stale pointer, reading from memory that has already been returned to the heap allocator.
Attack Vector
Exploitation requires an attacker to influence the runtime state of a long-lived Oj::Parser instance. An attacker who can supply JSON payloads to an application that toggles symbol_keys between parses can trigger the use-after-free condition. The impact depends on what data has been reallocated into the freed region between the cache_free call and the subsequent cache_intern read. Refer to the GitHub Security Advisory for reproduction details.
Detection Methods for CVE-2026-54899
Indicators of Compromise
- Unexpected SIGSEGV or SIGABRT crashes in Ruby processes loading the Oj native extension
- AddressSanitizer or Valgrind reports flagging cache_intern reads on freed memory
- Anomalous Ruby worker restarts following JSON parsing of attacker-controlled input
Detection Strategies
- Inventory Ruby applications and Gemfile.lock entries to identify Oj versions prior to 3.17.2
- Perform static review of application code for calls that reconfigure symbol_keys on shared Oj::Parser instances
- Run test suites under memory safety tooling such as ASan to surface use-after-free reads in the Oj C extension
Monitoring Recommendations
- Alert on repeated Ruby process crashes correlated with inbound JSON traffic
- Capture core dumps from application workers to identify faults originating in cache_intern
- Track deployment of the fixed 3.17.2 release across production and staging environments
How to Mitigate CVE-2026-54899
Immediate Actions Required
- Upgrade the Oj gem to version 3.17.2 or later across all Ruby environments
- Audit application code for reuse of Oj::Parser instances where symbol_keys is toggled at runtime
- Rebuild and redeploy container images and packaged artifacts that bundle the vulnerable gem
Patch Information
The maintainers fixed CVE-2026-54899 in Oj version 3.17.2. The patch ensures the cache pointer is cleared after cache_free executes in opt_symbol_keys_set, preventing subsequent cache_intern calls from dereferencing freed memory. See the GitHub Security Advisory GHSA-2cw7-v8ff-p88r for full patch details.
Workarounds
- Avoid toggling symbol_keys on reused Oj::Parser instances; instantiate a new parser instead
- Set symbol_keys once during parser initialization and treat it as immutable for the parser lifetime
- Restrict acceptance of untrusted JSON on code paths that manipulate parser options dynamically
# Configuration example
bundle update oj --conservative
grep -R "Oj::Parser" ./app ./lib
bundle exec ruby -e 'require "oj"; puts Oj::VERSION'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

