Listen to this Post
The Oj gem for Ruby is a widely used, high-performance JSON parser and serializer. A critical vulnerability has been discovered in the `Oj::Doceach_child` method, which allows for a reliable Denial of Service (DoS) attack. An attacker can exploit this flaw by providing a specially crafted, deeply nested JSON document to any endpoint that processes untrusted JSON using the `Oj::Doc.open` method in conjunction with a recursive call to each_child.
The root cause of this vulnerability is a two-step chain of errors within the `ext/oj/fast.c` file, specifically in the `doc_each_child` function. First, the function increments a `doc->where` pointer past the end of a fixed-size `where_path` array (MAX_STACK = 100) without performing any bounds checking. Furthermore, it fails to decrement this pointer (doc->where-- is missing), meaning that a recursive call from within the yield block will continuously drive the `doc->where` pointer beyond the allocated array.
On a subsequent entry to the function, it copies the current path into a stack-local buffer, Leaf save_path
</code>. The size of the copy is calculated based on the `doc->where` pointer. When the previous recursive call has pushed `doc->where` past the `where_path[bash]` array, this calculated length (<code>wlen</code>) exceeds <code>MAX_STACK</code>. This leads to a `memcpy` operation that overflows the `save_path` buffer on the C stack.
The `Oj::Doc` parser does not impose a limit on JSON nesting depth; it relies on a C-stack pressure check which is insufficient to prevent this overflow. Consequently, a deeply nested attacker-controlled input can reach this vulnerable code path. On builds with stack protection enabled (the default, <code>-fstack-protector-strong</code>), the stack canary detects the corruption and aborts the process, resulting in a denial of service. The initial heap out-of-bounds write that occurs before the stack overflow is masked by the subsequent crash, and no other impact has been demonstrated.
The issue was reported by Zac Wang (@7a6163) and is fixed in version 3.17.3. The fix introduces a bounds check before incrementing `doc->where` and properly restores the pointer after the loop, raising a clean `Oj::DepthError` instead of aborting.
<h2 style="color: blue;">DailyCVE Form</h2>
Platform: .......
<h2 style="color: blue;">Oj gem for Ruby</h2>
Version: ........
<h2 style="color: blue;">< 3.17.3</h2>
Vulnerability :......
<h2 style="color: blue;">Stack Buffer Overflow</h2>
Severity: .......
<h2 style="color: blue;">High (DoS)</h2>
date: ..........
<h2 style="color: blue;">2026</h2>
<h2 style="color: blue;">Prediction: .......</h2>
<h2 style="color: blue;">2026-06-26</h2>
<h2 style="color: blue;">What Undercode Say</h2>
The vulnerability analysis reveals a classic case of improper bounds checking in a C extension. The `doc_each_child` function fails to validate the `doc->where` index before incrementing it, leading to a stack buffer overflow. The following technical details are critical for understanding and reproducing the issue.
<h2 style="color: blue;">Vulnerable Code Snippet (ext/oj/fast.c):</h2>
[bash]
define MAX_STACK 100
// ...
Leaf save_path[bash]; // 800-byte stack buffer
size_t wlen = doc->where - doc->where_path;
if (0 < wlen) {
memcpy(save_path, doc->where_path, sizeof(Leaf) (wlen + 1));
}
Proof of Concept (PoC):
require 'oj'
depth = 200
payload = '[' depth + '1' + ']' depth
Oj::Doc.open(payload) do |doc|
r = lambda { doc.each_child { |_| r.call } }
r.call
end
This script will cause an abort on vulnerable versions (depth >= 101), while a fixed version will raise Oj::DepthError.
Exploit
An attacker can reliably trigger a Denial of Service (DoS) by sending a JSON payload with a nesting depth of 101 or greater to any application endpoint that uses the vulnerable pattern. The exploit is trivial to execute and requires no special privileges.
1. Craft Payload: Create a JSON string with a nesting depth of at least 101. For example, a string like '[' 101 + '1' + ']' 101.
2. Deliver Payload: Submit this payload to a vulnerable endpoint that processes JSON with `Oj::Doc.open` and recursively iterates over it using each_child.
3. Trigger Crash: The application will process the payload, causing a stack buffer overflow. On systems with stack protection, this will immediately abort the process, leading to a denial of service.
Example of a vulnerable code pattern:
def process_json(json_string)
Oj::Doc.open(json_string) do |doc|
recursive_process(doc)
end
end
def recursive_process(doc)
doc.each_child { |child| recursive_process(child) }
end
Protection
Detection
- Version Check: The primary method of detection is to check the version of the `oj` gem in use.
gem list oj
Versions prior to `3.17.3` are vulnerable.
Mitigation
- Immediate Upgrade: The most effective protection is to upgrade the `oj` gem to version `3.17.3` or later.
gem update oj
- Input Validation: As a temporary workaround, implement input validation to reject JSON payloads with an excessive nesting depth before they reach the vulnerable code.
MAX_NESTING = 100 def safe_nesting?(json_string) depth = 0 json_string.each_char do |char| depth += 1 if char == '[' depth -= 1 if char == ']' return false if depth > MAX_NESTING end true end
- Avoid Recursive Patterns: Refactor code to avoid recursive patterns with `each_child` on untrusted input until the upgrade is applied.
Impact
- Denial of Service (DoS): The primary and demonstrated impact is a reliable crash of the Ruby process, leading to a denial of service. Any service that processes untrusted JSON with the vulnerable pattern is at risk.
- Service Disruption: This vulnerability can be exploited to repeatedly crash application instances, making the service unavailable to legitimate users.
- Potential for Further Exploitation: While not demonstrated, the initial out-of-bounds write into the `struct _doc` fields on the heap could, in theory, be leveraged for more severe impacts, such as information disclosure or remote code execution, under specific and unlikely circumstances. However, the stack overflow reliably crashes the process first, masking this potential.
🎯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

