Cloudanix VulnDB

CVE-2026-54592

High · 7.5

CVSS

7.5

EPSS

0.3%

Published

Jul 1, 2026

CISA due date

—

Cloudanix analysis

Next patch cycle SSVC: Track

A specially crafted JSON input can crash affected Ruby applications that use an older JSON parsing library, potentially making services unavailable.

Exploitation
Remote Unauthenticated
Attacker needs
None
Complexity
Low
Impact
Denial Of Service
Component
Library
Class
Buffer Overflow
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

Oj versions prior to 3.17.3 contain a stack-based buffer overflow in the Oj::Doc#each_child traversal path. When application code recursively invokes each_child while processing a deeply nested JSON document, internal path tracking can advance past a fixed-size stack array without bounds checking and is not restored correctly. A subsequent traversal copies an oversized path into a fixed 800-byte stack-local buffer, causing memory corruption and process abort. The practical impact is unauthenticated remote denial of service when attacker-controlled JSON can reach vulnerable recursive Oj::Doc processing.

Why it matters to the business

Applications or services that parse untrusted JSON with vulnerable Oj versions can be crashed by a crafted deeply nested JSON payload, causing service interruptions, failed API requests, job processing failures, and potential cascading outages if affected Ruby processes are repeatedly restarted and re-crashed. Although current public exploitation maturity and EPSS are low and this is not listed in CISA KEV, the flaw is network-reachable in common API patterns and has high availability impact, so internet-facing or high-throughput JSON ingestion paths should be prioritized.

How an attack unfolds

An attacker identifies an endpoint, background job input, webhook receiver, message consumer, or file import path that accepts JSON and is processed by Ruby code using Oj::Doc#each_child recursively. The attacker sends a JSON document with sufficient nesting depth and structure to drive recursive child traversal. Because vulnerable Oj versions do not correctly bound or restore the internal traversal pointer, repeated recursive calls move the pointer beyond the fixed where_path array. On a later call, Oj copies more entries than the destination stack buffer can hold, corrupting stack memory. The process then aborts, typically producing a crash, core dump, container restart, worker death, or HTTP 5xx response. Repeating the request can sustain a denial-of-service condition.

How to fix it

Upgrade the Oj Ruby gem to version 3.17.3 or later everywhere it is used. Rebuild and redeploy application images, dependency bundles, serverless packages, and worker runtimes so the fixed native extension is actually loaded. If immediate upgrade is not possible, reduce exposure by rejecting or limiting deeply nested JSON before it reaches Oj, enforcing strict request body size and JSON nesting-depth limits, avoiding recursive Oj::Doc#each_child traversal on untrusted input, and isolating JSON-processing workers with restart limits and resource controls. Ensure dependency lockfiles are updated and that transitive or vendored copies of Oj are not left behind in packaged artifacts.

How to confirm the fix worked

Confirm remediation by checking the resolved Oj version in every runtime artifact, not only source manifests. For Bundler-based applications, verify Gemfile.lock resolves oj to 3.17.3 or later and run `bundle exec ruby -roj -e 'puts Oj::VERSION'` inside the deployed container or host image. Review dependency scanners, SBOMs, and package inventories for oj versions earlier than 3.17.3. Exercise representative JSON ingestion paths with safe depth-limit tests to confirm oversized or deeply nested JSON is rejected gracefully and does not crash the Ruby process. Monitor post-deployment error rates, process restarts, and crash logs to confirm no recurrence of Oj-related aborts.

Typical attack path

  1. Find a JSON ingestion point in a Ruby service, API, worker, webhook, or import workflow.
  2. Confirm or infer that the application uses the Oj Ruby gem and recursive Oj::Doc#each_child traversal on attacker-controlled JSON.
  3. Craft a deeply nested JSON payload designed to trigger recursive each_child execution beyond the internal MAX_STACK path limit.
  4. Submit the payload over the exposed interface, such as an HTTP request, queued message, uploaded file, or webhook event.
  5. Cause the vulnerable Ruby process to abort due to stack buffer overflow during Oj traversal.
  6. Repeat delivery to keep processes crashing and degrade or deny service availability.

How to detect it

Look for evidence of process crashes or restarts correlated with receipt of unusually large or deeply nested JSON payloads. Relevant sources include application logs, web/API gateway logs, reverse proxy logs, Ruby exception and stderr logs, container runtime events, orchestrator restart history, systemd journals, crash dumps, core files, APM traces, and message queue dead-letter or retry logs. Focus on repeated HTTP 5xx responses, worker exits, container CrashLoopBackOff events, SIGABRT or SIGSEGV terminations, stack-smashing messages, and native stack traces referencing Oj, oj/fast, Oj::Doc, or each_child. Network and request logs may show POST/PUT/PATCH requests with very high nesting density, excessive braces/brackets, or request bodies that repeatedly precede process termination. Because exploitation causes denial of service rather than a reliable persistent artifact, absence of file-system IOCs does not prove absence of attempts; correlation between crafted JSON inputs and crashes is the strongest signal.

  • Oj::Doc#each_child
  • Oj::Doc
  • each_child
  • oj/fast
  • ext/oj/fast.c
  • Oj::VERSION
  • stack smashing detected
  • *** stack smashing detected ***
  • Aborted (core dumped)
  • Segmentation fault
  • SIGABRT
  • SIGSEGV
  • core dumped
  • CrashLoopBackOff
  • where_path
  • save_path
  • MAX_STACK

What your security team should do

  • Inventory Ruby applications, containers, serverless functions, and worker images for the Oj gem and prioritize any version earlier than 3.17.3.
  • Patch or rebuild affected deployments to Oj 3.17.3 or later, starting with internet-facing APIs, webhook receivers, file importers, and message consumers that process untrusted JSON.
  • Add application-layer JSON depth and request-size limits at API gateways, reverse proxies, and application validation layers.
  • Search logs and crash artifacts for historical Oj-related process aborts, stack smashing messages, segmentation faults, and repeated crashes following JSON requests.
  • Add regression tests for deeply nested JSON inputs and ensure parsing failures return controlled errors rather than terminating the process.
  • Track dependency lockfiles and SBOMs to prevent older Oj versions from being reintroduced through pinned gems, base images, or vendored packages.

The record

Oj (Optimized JSON) is a JSON parser and Object marshaller packaged as a Ruby gem. In versions prior to 3.17.3, Oj::Doc#each_child, when invoked recursively over a deeply nested JSON document, overflows a fixed-size stack buffer and aborts the process, leading to DoS. In a two-step chain in ext/oj/fast.c, doc_each_child increments doc->where past the where_path[MAX_STACK = 100] array with no bounds check and never restores it (the doc->where-- is missing), so calling each_child recursively from inside the yield block drives doc->where beyond the array. On the next entry the function copies the path into the 800-byte stack-local buffer save_path[MAX_STACK] using wlen = doc->where - doc->where_path, so when the previous recursive call left doc->where past where_path[100] the wlen exceeds MAX_STACK and the memcpy overflows save_path on the C stack; because the Oj::Doc parser imposes no JSON nesting-depth limit (relying on a C-stack pressure check), deeply nested attacker input reaches this path. This issue has been fixed in version 3.17.3.

Affected packages

Ecosystem Package Introduced Fixed

Related vulnerabilities