🛡️ CVE-2026-71847 — json

🟢 CVSS 2.0 — Low ✅ No Known Exploit CWE-416 NVD
2.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Ruby JSON: JSON::ResumableParser#partial_value dereferences a freed input buffer and crashes on truncated duplicate-key streams

Summary

Ruby's JSON native C extension clears the consumed JSON::ResumableParser input buffer but leaves state.start, state.cursor, and state.end pointing into released storage.

When partial_value reconstructs an incomplete object containing duplicate keys, the duplicate-key warning path calls cursor_position, which dereferences those stale pointers. This results in a heap-use-after-free and can terminate the Ruby process.

An attacker who can supply JSON stream data to an application using JSON::ResumableParser may cause process termination when the application calls partial_value on incomplete attacker-controlled input containing duplicate object keys.

The issue was reproduced in the native C extension from the official RubyGems releases:

  • JSON 2.20.0
  • JSON 2.21.0
  • JSON 2.21.1

The attached evidence demonstrates:

  • an AddressSanitizer-confirmed heap-use-after-free;
  • a native SIGSEGV using the official JSON 2.21.1 RubyGem;
  • an end-to-end loopback TCP attacker/victim reproduction;
  • four differential controls;
  • successful execution after applying a tested patch control.

This was originally reported privately through Ruby's HackerOne program as report #3867755. A Ruby maintainer independently confirmed reproduction of the ASan failure and requested that further coordination continue through this private advisory.

No code execution or information disclosure is claimed.

Details

The affected source is:

```text

ext/json/ext/parser/parser.c

```

The vulnerable sequence in JSON 2.21.1 is:

1. cResumableParser_parse reaches the end of the current input buffer.

2. It calls json_str_clear(parser->buffer).

3. It sets parser->buffer = Qfalse.

4. The parser-state pointers into the released buffer are not reset.

5. partial_value makes a shallow copy of the parser state.

6. Reconstructing an incomplete object containing duplicate keys reaches the duplicate-key warning path.

7. cursor_position walks through the stale input pointers and reads released memory.

Relevant source locations:

  • Buffer release:

https://github.com/ruby/json/blob/fd61def38b9bb859fee7eec8e7d3143600e5b347/ext/json/ext/parser/parser.c#L2562-L2569

  • Parser-state copy:

https://github.com/ruby/json/blob/fd61def38b9bb859fee7eec8e7d3143600e5b347/ext/json/ext/parser/parser.c#L2647-L2654

  • Stale-pointer read in cursor_position:

https://github.com/ruby/json/blob/fd61def38b9bb859fee7eec8e7d3143600e5b347/ext/json/ext/parser/parser.c#L590-L628

  • Duplicate-key handling path:

https://github.com/ruby/json/blob/fd61def38b9bb859fee7eec8e7d3143600e5b347/ext/json/ext/parser/parser.c#L1196-L1255

When input is supplied to the resumable parser, the parser state stores direct pointers into the backing Ruby string:

```c

RSTRING_GETMEM(parser->buffer, start, len);

parser->state.start = start;

parser->state.end = start + len;

parser->state.cursor = parser->state.start + offset;

```

After the current buffer has been consumed, cResumableParser_parse clears the string and removes the parser's reference to it:

```c

if (eos(&parser->state)) {

json_str_clear(parser->buffer);

parser->buffer = Qfalse;

}

```

This path does not invalidate or replace:

```text

parser->state.start

parser->state.cursor

parser->state.end

```

JSON::ResumableParser#partial_value subsequently makes a shallow copy of the parser structure:

```c

JSON_ResumableParser *original_parser = cResumableParser_get(self);

JSON_ResumableParser parser = *original_parser;

```

When the partial object contains duplicate keys, reconstruction follows this call path:

```text

cResumableParser_partial_value_body

-> json_decode_object

-> json_on_duplicate_key

-> emit_duplicate_key_warning

-> emit_parse_warning

-> cursor_position

```

cursor_position then reads through pointers that may refer to released storage.

AddressSanitizer reports:

```text

ERROR: AddressSanitizer: heap-use-after-free

cursor_position at parser.c:604

freed by cResumableParser_parse at parser.c:2567

```

The reproducer follows the normal resumable-parser API sequence:

```ruby

parser << chunk

parser.parse

parser << next_chunk

parser.parse

parser.partial_value

```

The issue does not require:

  • an application-defined callback;
  • explicit garbage collection;
  • parser reentrancy;
  • custom parser options;
  • an attacker-supplied Ruby object;
  • manual modification of native parser state.

The release-build crash reproduced on JSON 2.20.0, 2.21.0, and 2.21.1.

This report covers the native C-extension implementation. The separate Java-platform implementation was not tested and is not claimed to be affected.

PoC

The complete evidence bundle is attached as:

```text

ruby-json-resumable-partial-value-uaf-evidence-20260716.zip

```

SHA-256:

```text

07bf8d47b115e45d6145d0447ab6c1c0255e4a7e9b2fb55c3c9a0e24406134ac

```

Requirements

  • L

Weakness class

CVE-2026-71847 is classified as CWE-416: Use After Free. Memory is used after being released, so its contents may already belong to something else.

Affected software

CVE-2026-71847 is recorded against 2 packages.

  • json (from 2.20.0 up to 2.21.2)
  • unknown

Timeline and source

Published on 7 August 2026 and last revised on 8 August 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

github.com (Web)
github.com (Package)

Details

Severity LOW
CVSS Score 2.0
CVSS Vector N/A
CWE CWE-416
Public Exploit ✅ No
Source NVD
Published 2026-08-07
Updated 2026-08-12
Modified 2026-08-08
Fix URL N/A

Affected Packages

Software From version Fixed in
json 2.20.0 2.21.2
unknown

Similar Threats

Free Vulnerability Check

Is your site affected by CVE-2026-71847?

BotEraser helps you identify potentially vulnerable plugins and themes by checking your installation against CVE-2026-71847 and other known CVE records.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.