Skip to main content

Oj (Ruby gem) CVE-2026-54592

HIGH
Out-of-bounds Read (CWE-125)
2026-06-19 https://github.com/ohler55/oj GHSA-3m6q-jj5j-38c9
7.5
CVSS 3.1 · Vendor: https://github.com/ohler55/oj
Share

Severity by source

Vendor (https://github.com/ohler55/oj) PRIMARY
7.5 HIGH
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
vuln.today AI
7.5 HIGH

Remote unauthenticated JSON input crashes the worker with no C/I impact; stack canary makes the outcome a reliable abort, so A:H and AC:L.

3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Primary rating from Vendor (https://github.com/ohler55/oj).

CVSS VectorVendor: https://github.com/ohler55/oj

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High

Lifecycle Timeline

2
Source Code Evidence Fetched
Jun 19, 2026 - 21:26 vuln.today
Analysis Generated
Jun 19, 2026 - 21:26 vuln.today

DescriptionCVE.org

Summary

Oj::Doc#each_child, when invoked recursively over a deeply nested JSON document, overflows a fixed-size stack buffer and aborts the process. This is a denial of service reachable from untrusted JSON.

Details

Two-step chain in ext/oj/fast.c:

  1. doc_each_child (~line 1501) increments doc->where past the

where_path[MAX_STACK = 100] array with no bounds check, and never restores it (doc->where-- is missing). Calling each_child recursively from inside the yield block therefore drives doc->where beyond the array.

  1. On the next entry (~line 1478) the function copies the path into a

stack-local buffer:

c
   Leaf  save_path[MAX_STACK];           // 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));
   }

When the previous recursive call left doc->where past where_path[100], wlen exceeds MAX_STACK and the memcpy overflows save_path on the C stack.

The Oj::Doc parser imposes no JSON nesting-depth limit (it relies on a C-stack pressure check), so deeply nested attacker input reaches this path.

Proof of Concept

ruby
require 'oj'
depth = 200
payload = '[' * depth + '1' + ']' * depth
Oj::Doc.open(payload) do |doc|
  r = lambda { doc.each_child { |_| r.call } }
  r.call
end

Recursion depth <= 99 iterates normally; depth >= 101 aborts. lldb backtrace on the affected build (ruby 3.3.8 / arm64-darwin24):

SIGABRT
#2 __abort
#3 __stack_chk_fail
#4 doc_each_child   (oj.bundle, fast.c)

Impact

Reliable denial of service: any endpoint that calls Oj::Doc.open(untrusted) { |d| d.each_child ... } recursively can be crashed with a small deeply-nested payload. On builds with a stack protector (the default, -fstack-protector-strong) the canary aborts the process before the saved return address is used. The Step-1 heap OOB writes into struct _doc fields do occur, but are masked in practice because the Step-2 stack overflow crashes first; turning them into anything beyond a crash has not been demonstrated.

Patches

Fixed in 3.17.3: doc_each_child now bounds-checks before incrementing doc->where (raising Oj::DepthError) and restores doc->where after the loop, matching the existing each_leaf pattern. Verified on the fixed build: depth >= 101 raises a clean Oj::DepthError instead of aborting.

Credit

Reported by Zac Wang (@7a6163).

AnalysisAI

Denial of service in the Oj Ruby JSON parser (versions <3.17.3) allows remote unauthenticated attackers to crash any process that parses untrusted JSON via Oj::Doc.open followed by a recursive each_child call. A deeply nested JSON document drives doc->where past the 100-element where_path array, causing a subsequent memcpy to overflow an 800-byte stack buffer and trigger the stack canary (SIGABRT). …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Recon
Identify endpoint parsing JSON with Oj::Doc
Delivery
Send deeply nested JSON payload
Exploit
Trigger recursive each_child loop
Install
Overrun where_path past MAX_STACK=100
C2
memcpy overflows save_path stack buffer
Execute
Stack canary aborts worker (SIGABRT)
Impact
Sustained denial of service

Vulnerability AssessmentAI

Exploitation Requires the target application to (a) use the Oj::Doc API specifically - Oj::Doc.open on attacker-controlled JSON - and (b) call Oj::Doc#each_child recursively from inside its own yield block (the documented vulnerable pattern). … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment The CVSS 3.1 vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (7.5) is consistent with the description: a remote unauthenticated attacker can crash a process by sending a small, deeply-nested JSON payload, with no confidentiality or integrity impact. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An attacker posts a small JSON body such as '[' * 200 + '1' + ']' * 200 to any HTTP endpoint whose handler does Oj::Doc.open(body) { |d| recurse(d) } with a recursive each_child walk. On the 101st recursion the stack canary fires and the worker process aborts (SIGABRT), dropping in-flight requests; repeating the request keeps killing workers and causes a sustained service outage. …
Remediation Vendor-released patch: upgrade the oj gem to 3.17.3 or later, where doc_each_child now bounds-checks doc->where before incrementing it (raising Oj::DepthError) and restores it after the yield loop, mirroring the existing each_leaf pattern; the fix is documented in GHSA-3m6q-jj5j-38c9. … Detailed patch versions, workarounds, and compensating controls in full report.

Recommended ActionAI

24 hours: Identify all systems running Oj <3.17.3 and catalog instances parsing untrusted JSON. …

Sign in for detailed remediation steps and compensating controls.

Threat intelligence, references, and detailed analysis are available after sign-in.

Share

CVE-2026-54592 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy