Skip to content

Commit b3fbb6e

Browse files
committed
zlib: throw on out-of-bounds write buffers
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com> PR-URL: nodejs-private/node-private#931 Refs: https://hackerone.com/reports/3857258 CVE-ID: CVE-2026-58045
1 parent 064d339 commit b3fbb6e

2 files changed

Lines changed: 43 additions & 2 deletions

File tree

src/node_zlib.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,15 +518,19 @@ class CompressionStream : public AsyncWrap,
518518
if (!args[2]->Uint32Value(context).To(&in_off)) return;
519519
if (!args[3]->Uint32Value(context).To(&in_len)) return;
520520

521-
CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
521+
if (!Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf))) {
522+
return THROW_ERR_OUT_OF_RANGE(env, "input buffer is out of bounds");
523+
}
522524
in = Buffer::Data(in_buf) + in_off;
523525
}
524526

525527
CHECK(Buffer::HasInstance(args[4]));
526528
Local<Object> out_buf = args[4].As<Object>();
527529
if (!args[5]->Uint32Value(context).To(&out_off)) return;
528530
if (!args[6]->Uint32Value(context).To(&out_len)) return;
529-
CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
531+
if (!Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf))) {
532+
return THROW_ERR_OUT_OF_RANGE(env, "output buffer is out of bounds");
533+
}
530534
out = Buffer::Data(out_buf) + out_off;
531535

532536
CompressionStream* ctx;

test/parallel/test-zlib-invalid-input.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,43 @@ nonStringInputs.forEach(common.mustCall((input) => {
5252
});
5353
}, nonStringInputs.length));
5454

55+
const spoofedLength = new Uint8Array(1).fill(0x41);
56+
Object.defineProperty(spoofedLength, 'length', { get: () => 5000 });
57+
Object.defineProperty(spoofedLength, 'byteLength', { get: () => 5000 });
58+
59+
[
60+
zlib.deflateSync,
61+
zlib.gzipSync,
62+
zlib.deflateRawSync,
63+
zlib.unzipSync,
64+
zlib.inflateSync,
65+
zlib.gunzipSync,
66+
zlib.inflateRawSync,
67+
zlib.brotliCompressSync,
68+
zlib.brotliDecompressSync,
69+
zlib.zstdCompressSync,
70+
zlib.zstdDecompressSync,
71+
].forEach((method) => {
72+
assert.throws(() => {
73+
method(spoofedLength);
74+
}, {
75+
name: 'RangeError',
76+
code: 'ERR_OUT_OF_RANGE',
77+
});
78+
});
79+
80+
{
81+
const deflate = zlib.createDeflate();
82+
deflate._outOffset = deflate._chunkSize + 1;
83+
assert.throws(() => {
84+
deflate._processChunk(Buffer.alloc(1), zlib.constants.Z_FINISH);
85+
}, {
86+
name: 'RangeError',
87+
code: 'ERR_OUT_OF_RANGE',
88+
});
89+
deflate.close();
90+
}
91+
5592
unzips.forEach(common.mustCall((uz, i) => {
5693
uz.on('error', common.mustCall());
5794
uz.on('end', common.mustNotCall());

0 commit comments

Comments
 (0)