Listen to this Post
The Oj gem is a popular JSON parser and object marshaller for Ruby, prized for its speed. However, three of its `Oj::Doc` iterators — each_value, each_child, and `each_leaf` — contain a critical heap use-after-free vulnerability. The flaw resides in the C extension file ext/oj/fast.c, where each iterator follows a dangerous pattern: it yields control to a Ruby block via `rb_yield()` while iterating over a linked list of document nodes.
During this rb_yield(), the Ruby block can execute arbitrary code, including calling `doc.close` or `d.close` on the document or any child node. The `close` method invokes ruby_sized_xfree, which immediately frees the backing heap memory of the entire JSON document. When the block returns, the C iterator resumes execution and attempts to read `cur->next` from the now-freed memory region. This results in a classic use-after-free condition, where the program reads from a dangling pointer.
All three iterators are affected because they share the same flawed logic: they call `rb_yield()` and then advance the `cur` pointer without verifying that the document is still alive. An AddressSanitizer (ASAN) report for the `each_child` variant confirms the issue, showing a heap-use-after-free read at `doc_each_child` in fast.c:1505. The shadow bytes for the freed region are marked with
</code>, indicating a freed allocation.
This vulnerability is particularly dangerous because it can be triggered from pure Ruby code without any special privileges. An attacker who can control the JSON input and the block logic could potentially corrupt heap metadata, leading to denial of service, information disclosure, or even arbitrary code execution. The issue has been confirmed in the latest tested version, 3.17.1, and likely affects all versions that include the vulnerable `fast.c` file.
<h2 style="color: blue;">DailyCVE Form</h2>
<h2 style="color: blue;">| Field | Value |</h2>
<h2 style="color: blue;">|-|-|</h2>
<h2 style="color: blue;">| Platform | oj gem |</h2>
<h2 style="color: blue;">| Version | all versions |</h2>
<h2 style="color: blue;">| Vulnerability | heap use-after-free |</h2>
<h2 style="color: blue;">| Severity | high |</h2>
<h2 style="color: blue;">| Date | 2026-06-19 |</h2>
<h2 style="color: blue;">| Prediction | patch within weeks |</h2>
<h2 style="color: blue;">What Undercode Say: Analytics</h2>
The vulnerability manifests when a Ruby block closes the document during iteration. The following minimal reproduction demonstrates the issue for each iterator:
[bash]
require 'oj'
each_child – close the child node
Oj::Doc.open('[1,2]') { |doc| doc.each_child { |d| d.close } }
each_value – close the parent document
Oj::Doc.open('[1,2]') { |doc| doc.each_value { |v| doc.close } }
each_leaf – close the leaf node
Oj::Doc.open('[1,[bash]]') { |doc| doc.each_leaf { |d| d.close } }
All three snippets trigger the use-after-free because the `close` call frees the document’s heap memory while the C iterator still holds a pointer to the freed region.
How Exploit
An attacker can exploit this vulnerability by crafting a JSON document and a Ruby block that calls `close` during iteration. The ASAN report confirms the exact memory access pattern:
==253632==ERROR: AddressSanitizer: heap-use-after-free on address 0x5210000bd080 READ of size 8 at 0x5210000bd080 thread T0 0 doc_each_child /ext/oj/fast.c:1505 0x5210000bd080 is located 896 bytes inside of 4064-byte region [0x5210000bcd00, 0x5210000bdce0) freed by thread T0 here: 0 free 1 ruby_sized_xfree (libruby-3.3.so.3.3)
The shadow bytes for the freed region show [bash], confirming that the memory has been released and the subsequent read is invalid.
By controlling the timing and the heap layout, an attacker could potentially overwrite the freed memory with malicious data before the iterator reads cur->next, leading to control-flow hijacking or arbitrary code execution.
Protection
To protect against this vulnerability, developers should avoid calling `close` on a document or any of its nodes inside the block of each_value, each_child, or each_leaf. If closure is necessary, the iteration should be performed without using these iterators, or the document should be closed after the iteration completes.
Additionally, upgrading to a patched version of the oj gem (once available) is strongly recommended. Until a fix is released, consider using alternative JSON parsing methods that do not expose this iteration pattern.
Impact
- Denial of Service: The use-after-free can cause the Ruby process to crash with a segmentation fault, leading to application downtime.
- Information Disclosure: Reading from freed memory may expose sensitive data that was previously stored in the heap.
- Arbitrary Code Execution: In a controlled environment, an attacker could craft a heap spray to place malicious data in the freed region, potentially achieving remote code execution.
- Widespread Affected Versions: All versions of the oj gem that include `ext/oj/fast.c` are vulnerable, with the latest tested version (3.17.1) confirmed to be affected.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

