Where
AND
-Infinity
0
Severity
3.7
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

Impact

When undici parses a Set-Cookie header, it accepts any SameSite attribute value that contains Strict, Lax, or None as a substring, rather than the case-insensitive exact match specified by RFC 6265. Non-spec values are silently mapped to one of the three standard tokens:

- SameSite=NoneOfYourBusiness is parsed as None, the most permissive setting. - SameSite=StrictLax is parsed as Lax, a downgrade from Strict.

Affected applications are those that consume Set-Cookie headers from server responses (for example via undici's fetch or proxy code paths) and then forward or rely on the parsed sameSite attribute. A malicious or non-compliant server can coerce the consumer's view of a cookie's SameSite policy to a weaker value, silently degrading the SameSite enforcement the cookie is supposed to provide.

This was introduced in undici 5.15.0 when the cookies feature was added.

Patches

Upgrade to undici v6.27.0, v7.28.0 or v8.5.0.

Workarounds

After parsing a Set-Cookie header, validate that the resulting sameSite attribute is one of 'Strict', 'Lax', or 'None' (exact, case-insensitive) before forwarding or relying on it.

1 / 3
Source: GitHub
First published (updated )
Severity
3.7
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

Impact

Undici's HTTP/1.1 client is vulnerable to response queue poisoning on reused keep-alive sockets. An attacker-controlled upstream server can inject an unsolicited HTTP/1.1 response onto an idle socket after a request completes. When the client dispatches the next request on that socket, it associates the injected response with the new request, causing responses to be delivered to the wrong requests.

This requires an attacker-controlled or compromised upstream HTTP/1.1 server and keep-alive connection reuse.

Patches

Upgrade to undici v6.27.0, v7.28.0 or v8.5.0.

Workarounds

Disable keep-alive connection reuse by setting keepAliveTimeout: 0 on the Client or Pool.

1 / 2
Source: GitHub
First published (updated )
Severity
2.1
Use After Free
CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

Oj::Doc iterators (eachvalue, eachchild, eachleaf) are vulnerable to a heap use-after-free. When a Ruby block yielded during iteration calls doc.close or d.close, the document's heap memory is freed while the C iterator is still running. When control returns from the block, the iterator reads from the freed region, producing a use-after-free accessible from pure Ruby.

Version

- Software: oj gem - Affected: all versions with ext/oj/fast.c - Latest tested: 3.17.1 (confirmed present)

Details

The iterators in ext/oj/fast.c follow the pattern:

c // fast.c:1505 (doceachchild) static VALUE doceachchild(VALUE self, ...) { ... while (cur != NULL) { rbyield(...); // ← Ruby block executes here cur = cur->next; // ← cur is now freed if block called close() } }

rbyield can invoke arbitrary Ruby code, including calling close() on the Doc or any child node, which calls rubysizedxfree on the backing buffer. On return, the C code reads cur->next from the freed region. All three iterators are affected.

ASAN report (eachchild variant): ==253632==ERROR: AddressSanitizer: heap-use-after-free on address 0x5210000bd080 READ of size 8 at 0x5210000bd080 thread T0 #0 doceachchild /ext/oj/fast.c:1505 0x5210000bd080 is located 896 bytes inside of 4064-byte region [0x5210000bcd00, 0x5210000bdce0) freed by thread T0 here: #0 free #1 rubysizedxfree (libruby-3.3.so.3.3)

All three iterators trigger the same freed region (fd shadow bytes): 0x5210000bd080:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd

Reproduce

ruby require 'oj' eachchild Oj::Doc.open('[1,2]') { |doc| doc.eachchild { |d| d.close } } eachvalue Oj::Doc.open('[1,2]') { |doc| doc.eachvalue { |v| doc.close } } eachleaf Oj::Doc.open('[1,[2]]') { |doc| doc.eachleaf { |d| d.close } }

1 / 2
Source: GitHub
First published (updated )
Severity
2.1
Buffer Overflow
CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

Oj.dump in object mode is vulnerable to a heap buffer overflow when serializing Exception objects with a large :indent value. The serializer allocates a buffer sized for the object's attributes but does not account for the indent bytes added on each write. With indent: 5000, the accumulation of 5,000-byte indent strings overflows the 13,150-byte heap allocation, corrupting adjacent heap memory.

Version

- Software: oj gem - Affected: all versions with ext/oj/dump.h - Latest tested: 3.17.1 (confirmed present)

Details

ext/oj/dump.h, line 75–77:

c static void fillindent(Out out, int depth) { if (0 < out->opts->indent) { memset(out->buf + out->cur, ' ', (sizet)(out->opts->indent depth));

When dumping an Exception object in :object mode, dumpobjattrs calls fillindent repeatedly for each attribute. The buffer is pre-allocated based on the serialized content but not the indentation overhead. With indent: 5000 the indent block for a nested object exceeds the remaining buffer space, producing a heap-buffer-overflow of size 5,000 at the end of the allocated region.

ASAN report: ==101656==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x527000022c5e WRITE of size 5000 at 0x527000022c5e thread T0 #0 memset #1 fillindent /ext/oj/dump.h:77 #2 dumpobjattrs /ext/oj/dumpobject.c:552 #3 dumpobj /ext/oj/dumpobject.c:80 #4 ojdumpobjval /ext/oj/dumpobject.c:708 #5 ojdumpobjtojsonusingparams /ext/oj/dump.c:817 #6 dumpbody /ext/oj/oj.c:1429 #7 dump /ext/oj/oj.c:1480 0x527000022c5e is located 0 bytes after 13150-byte region [0x52700001f900, 0x527000022c5e)

Reproduce

ruby require "oj" obj = Oj.load('{"^o":"RuntimeError"}', mode: :object) Oj.dump(obj, mode: :object, indent: 5000)

Workarounds

This is at the discretion of the developer and not a public facing option so the workaround is the develop should not use extreme indents and should not offer the option for users to dump Ruby data with unlimited indentation size.

1 / 2
Source: GitHub
First published (updated )
Severity
2.1
Use After Free
CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

Oj::Parser#parse is vulnerable to a heap use-after-free when a SAJ/SAJ2 callback mutates the input JSON string during parsing. The C engine holds a raw const byte pointer into the Ruby string's internal buffer. If a callback (e.g. hashstart) resizes the string — for example by calling String#replace with a longer value — Ruby reallocates the string buffer and frees the old one. The C parser's pointer is left dangling; the next character read at parser.c:607 is a use-after-free.

Version

- Software: oj gem - Affected: all versions with ext/oj/parser.c - Latest tested: 3.17.1 (confirmed present)

Details

ext/oj/parser.c, parserparse → parse:

c static VALUE parserparse(VALUE self, VALUE json) { const byte ptr = (const byte )StringValuePtr(json); // raw pointer into Ruby string // ... parse(p, ptr); // ptr used throughout; any realloc frees the backing buffer }

c // parser.c:607 static void parse(ojParser p, const byte json) { const byte b = json; // ... for (; '\0' != b; b++) { // ← UAF: reads freed memory after callback resizes json

Ruby's String#replace (or <<, gsub!, etc.) can trigger a reallocation of the string's internal buffer if the new content is larger than the embedded capacity, freeing the old buffer that ptr still points to.

ASAN report: ==372273==ERROR: AddressSanitizer: heap-use-after-free on address 0x51900008ed81 READ of size 1 at 0x51900008ed81 thread T0 #0 parse /ext/oj/parser.c:607 #1 parserparse /ext/oj/parser.c:1408 0x51900008ed81 is located 1 bytes inside of 1023-byte region [0x51900008ed80, 0x51900008f17f) freed by thread T0 here: #0 free #1 rubysizedxfree (libruby-3.3.so.3.3) Shadow bytes: [fd]fd fd fd fd fd ... (entire region freed)

Reproduce

ruby require 'oj'

class Mutator def initialize(json) = (@json = json; @done = false)

def hashstart(key) return if @done; @done = true @json.replace('x' 1000000) # triggers String realloc, frees original buffer end

def hashend(key); end def arraystart(key); end def arrayend(key); end def addvalue(value, key); end end

json = '{"a":1,"pad":"' + ('A' 1000) + '","z":2}' parser = Oj::Parser.new(:saj) parser.handler = Mutator.new(json) parser.parse(json)

1 / 2
Source: GitHub
First published (updated )
Severity
3.7
Buffer Overflow
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L

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, fbufferdoinccapa().

On the IO path, the buffer is grown to FBUFFERIOBUFFERSIZE (16383), but the early return checks total capacity instead of remaining capacity:

c if (RBUNLIKELY(fb->io)) { if (fb->capa < FBUFFERIOBUFFERSIZE) { fbufferrealloc(fb, FBUFFERIOBUFFERSIZE); } else { fbufferflush(fb); }

if (RBLIKELY(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. fbufferappendreserved() then writes past the buffer:

c MEMCPY(fb->ptr + fb->len, newstr, char, len);

The minimal fix is to compare against the remaining capacity:

diff - if (RBLIKELY(requested < fb->capa)) { + if (RBLIKELY(requested <= fb->capa - fb->len)) { return; }

PoC

ruby require "json" require "stringio"

io = StringIO.new big = "a" 16385 big[16382] = '"' # escapable byte near the buffer boundary

JSON.dump([big], io)

Verified results:

text 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 fbufferappendreserved ext/json/fbuffer/fbuffer.h:145 searchflush ext/json/generator/generator.c:139 convertUTF8toJSON ext/json/generator/generator.c:231 rawgeneratejsonstring ext/json/generator/generator.c:922 cStatemgenerate 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.

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203