CVE-2026-54500: Oj Ruby Gem Memory Leak via Long JSON Keys
Oj is a widely-used Ruby gem for parsing JSON data. A flaw in versions before 3.17.3 causes the parser to leak uninitialized memory from the process stack when it encounters JSON objects with very long keys (254 bytes or more). An attacker can craft a malicious JSON payload to trigger this memory leak, potentially exposing sensitive data that happened to be in memory at that moment. The vulnerability is reachable over the network if your application parses untrusted JSON input.
Source data · NVD / CISA · public domain
- CVSS
- 3.1 · 5.3 MEDIUM · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
- Weaknesses (CWE)
- CWE-125, CWE-908
- Affected products
- 0 configuration(s)
- Published / Modified
- 2026-07-01 / 2026-07-01
NVD description (verbatim)
Oj (Optimized JSON) is a JSON parser and Object marshaller packaged as a Ruby gem. In versions prior to 3.17.3, Oj.load in :object mode reads uninitialized stack memory (and, for long keys, reads out of bounds) when parsing a JSON object whose key is 254 bytes or longer. The interned bytes can surface to the caller, disclosing process stack memory. In ext/oj/intern.c, form_attr() handles the long-key path by allocating a heap buffer, `b`, populating it with the attribute name, and then freeing it — but it passed the uninitialized stack buffer buf (not b) to rb_intern3(). rb_intern3 therefore reads len + 1 bytes of uninitialized stack memory. When the key length is >= 256, it also reads out of bounds past the 256-byte buf. The resulting bytes are interned and can reach the caller via the produced Symbol or via the EncodingError message raised on invalid UTF-8, leaking process stack contents. This issue has been fixed in version 3.17.3.
1 reference(s) · View on NVD →
SEC.co analysis · AI-assisted, reviewed against source
Technical summary
CVE-2026-54500 is a memory-disclosure vulnerability in Oj's :object mode JSON parsing. The root cause lies in ext/oj/intern.c's form_attr() function, which handles long attribute names by allocating a temporary heap buffer but then passes an uninitialized stack buffer (buf, 256 bytes) to rb_intern3() instead of the populated heap buffer. This causes rb_intern3() to read len + 1 bytes of uninitialized stack memory. When key length exceeds 256 bytes, the function reads beyond buf's bounds entirely. The leaked bytes are subsequently interned as Ruby Symbols or embedded in EncodingError exception messages, making them observable by the caller. Affected CWE classifications are CWE-125 (Out-of-bounds Read) and CWE-908 (Use of Uninitialized Resource).
Business impact
Organizations running applications that parse JSON with Oj are exposed to information disclosure. If untrusted users can submit JSON payloads (e.g., via an API, form submission, or message queue), an attacker can extract fragments of process memory—potentially including secrets, authentication tokens, or other sensitive data resident on the stack. The leaked information becomes embedded in Symbol interning or error messages, making it accessible to the attacker. In multi-tenant environments or cloud deployments, this could leak cross-tenant data. The impact is limited to confidentiality; the vulnerability does not enable code execution, denial of service, or data modification.
Affected systems
Oj versions prior to 3.17.3 are vulnerable. Ruby applications that include Oj as a dependency and parse JSON in :object mode (the default marshalling mode) are at risk, particularly those accepting JSON input from untrusted sources. Applications that only parse JSON in other modes (e.g., :strict, :null, :json) or that exclusively parse trusted, internal JSON data face lower risk. Verify your Gemfile or gemspec to confirm which version of Oj you have installed and whether long keys are a realistic input vector in your use case.
Exploitability
Exploitability is straightforward: the vulnerability requires only network access and the ability to send a JSON object with a key ≥254 bytes to the target application. No authentication, user interaction, or complex setup is required. The CVSS 3.1 score of 5.3 (MEDIUM) reflects the low attack complexity and network accessibility, balanced against the confidentiality-only impact. However, the ease of triggering and deterministic nature of the leak make this a practical threat in any scenario where untrusted JSON input is processed.
Remediation
Upgrade Oj to version 3.17.3 or later. This version corrects form_attr() to pass the initialized heap buffer (b) to rb_intern3(), eliminating the uninitialized memory read. After patching, redeploy your Ruby application. If immediate patching is not possible, consider temporarily disabling JSON parsing of untrusted input or implementing a JSON key-length validation layer upstream to reject keys exceeding a reasonable threshold (e.g., 200 bytes).
Patch guidance
Update your Gemfile to require 'oj', '~> 3.17.3' or later, then run bundle update oj. Verify the new version with bundle list oj or by checking Gem::Specification.find_by_name('oj').version in a Rails console. Restart your application after updating. Test thoroughly in a staging environment to ensure no compatibility issues with your JSON parsing workflows. If you use Oj via a transitive dependency, trace the dependency tree (bundle show or bundler-audit) and ensure the parent gem also updates Oj or that you can pin Oj directly in your Gemfile.
Detection guidance
Monitor application logs for EncodingError or Symbol creation anomalies tied to JSON parsing. If Oj is instrumented with logging, look for repeated attempts to parse JSON with unusually long keys. Network-based detection is difficult because the payload is valid JSON; however, WAF rules or API gateway policies can flag requests with abnormally long JSON object keys (e.g., >1000 bytes). For forensic investigation, review process memory dumps or process stack traces around the time of suspected exploitation to identify leaked data. Enable Ruby's symbol_gc gem or monitor :Symbol objects for unexpected interning patterns if you suspect memory exfiltration.
Why prioritize this
Although classified as MEDIUM severity, this vulnerability warrants prompt attention because: (1) the attack surface is wide—any application parsing untrusted JSON is at risk; (2) exploitation is trivial and requires no special tools; (3) the leak exposes live process memory, which in modern applications often contains secrets, API keys, or user data; and (4) Ruby gems are frequently auto-updated or pinned transitively, potentially leaving applications behind. Prioritize patching for any services accepting external JSON input, especially APIs, webhooks, and data importers.
Risk score, explained
The CVSS 3.1 score of 5.3 is derived from: Network-accessible attack vector (AV:N), low attack complexity (AC:L), no privilege or user interaction required (PR:N, UI:N), and impact scoped to confidentiality only (C:L, I:N, A:N). The score correctly reflects the practical exploitability and low bar for triggering the leak, but should not minimize the risk of actual data exposure—leaked stack memory in production environments can contain high-value secrets. Organizations handling sensitive data should treat this as higher-priority than the numeric score alone suggests.
Frequently asked questions
Can this vulnerability be exploited without sending a request to my application?
No. The vulnerability requires sending a JSON payload with a long key to an application running vulnerable Oj code. If your app does not parse JSON input from external sources (e.g., it only reads pre-processed internal data), the attack surface is minimal. However, if your app consumes webhooks, APIs, file uploads, or message queue data, you are exposed.
What data could an attacker actually leak?
An attacker leaks whatever is on the process stack at the moment the JSON is parsed. In a typical Ruby application, this could include local variables, return addresses, fragments of exception messages, string literals, and occasionally secrets stored in memory. The leaked bytes surface as a Symbol name or within an EncodingError message, making them visible to the attacker in the response or log output.
Does upgrading to 3.17.3 require code changes?
No. The fix is entirely contained within Oj's C extension. Simply update the gem version and restart your application. You do not need to modify how you call Oj.load() or change any parsing logic.
What if I only use Oj for internal data that I control?
If all JSON you parse originates from trusted, internal sources (your own database, configuration files, or backend services you fully control), the risk is lower because an attacker cannot inject a long-key payload. However, supply chain or indirect injection risks still exist (e.g., if a dependency you use processes external JSON). It is still prudent to upgrade when convenient.
This analysis is based on the CVE-2026-54500 public disclosure and does not constitute security advice for any specific system. Testing and deployment decisions should be made in consultation with your security and engineering teams. SEC.co makes no warranty regarding the accuracy, completeness, or applicability of this information to your environment. Always verify patch versions and compatibility in your staging environment before production deployment. If you believe you have been compromised by exploitation of this vulnerability, engage incident response and threat intelligence professionals immediately. Source: NVD (public-domain), retrieved 2026-08-09. Analysis generated by SEC.co (claude-haiku-4-5).
Related vulnerabilities
- CVE-2026-48104MEDIUM7-Zip SquashFS Uninitialized Memory Read (CVSS 4.2)
- CVE-2020-9711MEDIUMAdobe Acrobat Reader Out-of-Bounds Read Memory Disclosure
- CVE-2020-9713MEDIUMAdobe Acrobat Reader Memory Disclosure Vulnerability
- CVE-2025-15661MEDIUMlibssh2 Out-of-Bounds Heap Read in SFTP Symlink Handling
- CVE-2025-70101MEDIUMlwext4 1.0.0 Out-of-Bounds Read Denial of Service
- CVE-2026-0127MEDIUMAndroid Out-of-Bounds Read in Communication Processor – Impact & Patch Guidance
- CVE-2026-0128MEDIUMAndroid RTCP Out-of-Bounds Read Information Disclosure
- CVE-2026-0136MEDIUMAndroid Modem Out-of-Bounds Read Denial of Service