eastbaycyber

CVE-2026-54592: Oj Ruby Gem Buffer Overflow DoS

CVE explainers 9 min read
SR
Security Research Desk Expert reviewed
Threat intelligence · Human-verified · Updated 2026-07-01
▲ Escalation ViewOne CVE, briefed at three altitudes — skim the Brief, weigh the Impact, or work the Runbook. The way a SOC actually reads it.
CISOBrief · 30-second brief
Field Value
CVE ID CVE-2026-54592
CVSS score 7.5 High
Attack vector Unknown from retrieved NVD response
Auth required None stated in available advisories; defenders should assume untrusted input can trigger it if reachable
Patch status Fixed in Oj 3.17.3

TL;DR - Oj before 3.17.3 can crash on deeply nested JSON during recursive Oj::Doc#each_child use. - Apps parsing attacker-controlled JSON with recursive traversal are affected. - Upgrade to 3.17.3+ quickly; no confirmed in-the-wild exploitation is currently established.

What This Vulnerability Is and Why It Matters

CVE-2026-54592 is a high-severity denial-of-service flaw in the Oj Ruby gem, also known as Optimized JSON. The issue affects all versions prior to 3.17.3 and is fixed in version 3.17.3. According to the published vulnerability description, the bug sits in Oj::Doc#each_child and is triggered when that method is invoked recursively over a deeply nested JSON document.

The practical impact is process termination. The vulnerability is described as a stack-based buffer overflow in native C code used by the gem. In the scenarios covered by the advisory, a crafted JSON payload can drive the parser into an invalid internal state and cause the process to abort. For defenders, this means the main concern is service availability rather than data theft or code execution. Still, availability issues matter in production APIs, background workers, webhook processors, and any Ruby service that accepts JSON from less-trusted sources.

A key point is reachability. Not every application using Oj is automatically vulnerable in practice. The issue specifically involves recursive invocation of Oj::Doc#each_child over deeply nested input. If your code never uses Oj::Doc traversal in that way, exposure may be lower. However, in the absence of code review evidence, defenders should assume risk exists anywhere untrusted JSON enters an application that depends on Oj versions < 3.17.3.

The published sources do not establish remote code execution, privilege escalation, or confirmed confidentiality impact. They do clearly establish denial of service through process crash. For internet-facing services, that is enough to justify accelerated patching, especially if JSON documents can be attacker-supplied and application workers restart slowly or exhaust upstream retry logic.

AnalystImpact · assess the risk

Affected Versions and Exposure Assessment

The affected product is the Oj Ruby gem, maintained by the Oj project. The published affected range is explicit: all versions prior to 3.17.3, commonly expressed as < 3.17.3. The fixed version is equally explicit: 3.17.3.

That version range matters for dependency management because Oj is often a transitive dependency or pinned indirectly in Ruby applications. Many teams know they use Rails, Sidekiq, Sinatra, or internal service frameworks, but do not always know which JSON gem versions are bundled into application images or lockfiles. If you operate Ruby workloads, check both direct dependencies in Gemfile.lock and built artifacts such as containers or packaged deployments.

Component Affected versions Fixed version
Oj gem < 3.17.3 3.17.3

Exposure depends on more than the installed version. You should prioritize systems that meet all of the following conditions: they run Oj below 3.17.3, they process attacker-influenced JSON, and they use Oj::Doc#each_child recursively or through application logic that leads to equivalent traversal behavior. If you cannot verify usage quickly, treat public-facing API services as higher risk than isolated internal jobs.

Because the available sources do not provide a full CVSS vector, network preconditions are not formally stated in the retrieved NVD response. Likewise, there is no authoritative vendor statement here on every framework or code path that could make the flaw reachable. In that uncertainty, defenders should assume realistic exploitability wherever user-controlled JSON meets vulnerable parsing code.

Exploitation Status and Risk Posture

At the time of writing, there is no confirmed evidence from the retrieved sources that exploitation is occurring in the wild. The vulnerability is not listed in CISA KEV based on the research note provided. That lowers immediate pressure compared with mass-exploited edge-device flaws, but it should not be read as a reason to defer patching indefinitely.

There is also no separate public proof-of-concept repository identified in the provided source set. However, the public vulnerability description is technically detailed. It explains the faulty pointer handling, the missing state restoration, and the overflow condition. That means a motivated researcher or attacker likely does not need much additional information to reproduce a crash in a lab environment.

For prioritization, this lands in the middle ground: no confirmed active exploitation, no known public PoC from the provided references, but enough implementation detail to expect reproduction is feasible. If your application is exposed to arbitrary JSON from customers, third parties, webhooks, or message queues, patching should still be treated as near-term operational work, not backlog cleanup.

Defenders should also keep in mind that denial-of-service vulnerabilities are often underreported operationally. An attacker does not need persistence or stealth if repeatedly crashing a service is enough to degrade business function. If your environment depends on worker autoscaling or retries, even a “simple crash” can become an expensive reliability incident.

Technical Impact and Root Cause

The root cause described in public records is a logic error in ext/oj/fast.c. In brief, doc_each_child increments an internal pointer, doc->where, without sufficient bounds checking against where_path[MAX_STACK = 100]. It also fails to restore that pointer correctly because a corresponding decrement is missing. Later, the code calculates a path length and copies it into a fixed-size stack buffer.

That sequence matters because the bug is not just “deep nesting is bad.” The advisory describes a two-step chain: internal traversal state moves past the intended bounds, and on a later entry the computed length exceeds the fixed-size local buffer. The result is a stack buffer overflow into save_path[MAX_STACK], causing process abort. The parser itself also does not impose a JSON nesting-depth limit according to the description, which helps attacker-controlled deeply nested input reach the vulnerable path.

Technical Notes

The available public explanation describes the vulnerable behavior in terms of native code state management:

// Conceptual summary from the public description, not a full source listing.
doc_each_child(...){
    doc->where++;              // incremented
    // missing effective bounds enforcement here
    // ...
    wlen = doc->where - doc->where_path;
    memcpy(save_path, doc->where_path, wlen * sizeof(...)); // overflows when wlen > MAX_STACK
    // missing doc->where-- restoration in the vulnerable path
}

The reported fix behavior for Oj 3.17.3 is that traversal now bounds-checks before incrementing doc->where, raises Oj::DepthError when depth would exceed limits, and restores doc->where after traversal. That change blocks the invalid internal state that enables the overflow.

What Defenders Should Do Next

First, identify every Ruby application, background worker, and container that includes Oj < 3.17.3. This should be a dependency inventory exercise, not just a source repository review. In many environments, the biggest gap is between “we updated the Gemfile” and “the running image actually contains the fixed gem.”

Second, prioritize internet-facing services and integration points that accept JSON from customers or third parties. If those services are high-availability systems, include SRE or platform teams in the response so restart loops, crash alerts, and autoscaling behavior are monitored during the patch window. Do not wait for public exploitation confirmation before taking action if your service availability matters.

Third, review code for Oj::Doc and recursive each_child usage. Even after patching, this review is useful because it highlights parsing pathways that deserve better validation, safer traversal limits, and more robust resilience testing with malformed or extreme inputs.

ResponderRunbook · act now

How to Detect Vulnerable Systems and Suspicious Activity

Start with asset and dependency detection. On Ruby hosts, CI runners, and container images, determine whether the installed Oj version is less than 3.17.3. That is your first and most reliable detection step. Then identify application code paths or gems that use Oj::Doc traversal, especially recursive each_child patterns. In practice, many teams will not have immediate code-level certainty, so version-based scoping is the fastest starting point.

Next, look for operational indicators of crash attempts or parser stress. Since this is a denial-of-service issue, the strongest signals may be worker exits, segmentation faults, aborts, container restarts, and request patterns carrying unusually deep JSON structures. The exact crash text can vary by Ruby version, libc, runtime, and deployment platform, so do not rely on a single string. Instead, correlate application errors, process terminations, and suspicious request bodies or payload sizes.

Technical Notes

Check the installed version locally:

bundle exec ruby -e 'require "oj"; puts Oj::VERSION'

Search the lockfile for vulnerable versions:

grep -n '^    oj ' Gemfile.lock

List the gem in a container or host:

bundle list | grep -i '^  \* oj '

Useful log patterns to hunt for include process aborts around JSON-handling endpoints. Example patterns:

Oj::Doc
each_child
stack level too deep
Aborted
SIGABRT
segmentation fault
worker exited

Example Splunk search:

index=app_logs ("Oj::Doc" OR "each_child" OR "SIGABRT" OR "Aborted" OR "segmentation fault")
| stats count by host, service, sourcetype

Example Elastic query string:

message:("Oj::Doc" OR "each_child" OR "SIGABRT" OR "Aborted" OR "segmentation fault")

If you have HTTP telemetry, look for endpoints receiving heavily nested JSON from untrusted clients. A crude but useful proxy is repeated { depth or arrays nested far beyond normal application behavior. Without a published network signature, defenders should use anomaly-based detection rather than assume a stable exploit fingerprint.

Mitigation and Patching Guidance

The primary remediation is straightforward: upgrade Oj to version 3.17.3 or later. If you manage Ruby applications through Bundler, update the gem, rebuild artifacts, and redeploy. This is the only published fix in the provided references, and it directly addresses the vulnerable traversal behavior.

Where immediate patching is not possible, your temporary mitigation is to reduce exposure to untrusted deeply nested JSON and avoid vulnerable recursive traversal patterns. That can mean rejecting abnormally nested documents at the application edge, limiting request body complexity, or disabling code paths that rely on recursive Oj::Doc#each_child processing. These are compensating controls, not full fixes, because the root issue remains in native code until the gem is updated.

If you cannot verify whether your application uses the vulnerable method, assume that any public or partner-facing JSON ingestion path is in scope. Temporary request filtering can buy time, but it will be less reliable than upgrading because application and parser behavior may vary and deeply nested payloads can arrive through APIs, job queues, file uploads, or webhook relays.

Technical Notes

Upgrade directly with Bundler:

bundle update oj

Or pin the fixed version in your Gemfile:

gem "oj", ">= 3.17.3"

Then install and verify:

bundle install
bundle exec ruby -e 'require "oj"; puts Oj::VERSION'

If you need a temporary application-layer workaround, reject excessive nesting before invoking Oj traversal logic. Example Ruby pseudocode:

def too_deep?(obj, max_depth = 100, depth = 0)
  return true if depth > max_depth

  case obj
  when Hash
    obj.any? { |_, v| too_deep?(v, max_depth, depth + 1) }
  when Array
    obj.any? { |v| too_deep?(v, max_depth, depth + 1) }
  else
    false
  end
end

If you use a reverse proxy or API gateway, consider request size and schema validation rules as a stopgap. This is imperfect because payload size alone does not equal nesting depth, but it can reduce easy crash attempts while patching is underway.

References

For further reading on related vulnerabilities, check out our articles on what is a buffer overflow and lateral movement.

This article may contain affiliate links. We earn a commission on qualifying purchases at no extra cost to you.

Last verified: 2026-07-01

Disclaimer: This article may contain affiliate links. We earn a commission on qualifying purchases at no extra cost to you.