From a404538a67ee61f7652c4d450d658e6e156081a4 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Thu, 11 Jun 2026 18:36:22 -0700 Subject: [PATCH] QuickJS: fix infinite loop on inflate of a stream needing a dictionary The qjs inflate loop treated only rc < 0 as an error. Z_NEED_DICT is positive, so a zlib stream with the FDICT flag and no dictionary made inflate() return Z_NEED_DICT with no progress every iteration, spinning forever and growing the output chain on attacker-controlled input. Handle Z_NEED_DICT explicitly, matching the njs zlib module. --- external/qjs_zlib_module.c | 5 +++++ test/zlib.t.mjs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/external/qjs_zlib_module.c b/external/qjs_zlib_module.c index 5abf108a..caeb2761 100644 --- a/external/qjs_zlib_module.c +++ b/external/qjs_zlib_module.c @@ -415,6 +415,11 @@ qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc, goto fail; } + if (rc == Z_NEED_DICT) { + JS_ThrowTypeError(ctx, "failed to inflate, dictionary is required"); + goto fail; + } + njs_chb_written(&chain, chunk_size - stream.avail_out); } diff --git a/test/zlib.t.mjs b/test/zlib.t.mjs index faef1fb0..612a4198 100644 --- a/test/zlib.t.mjs +++ b/test/zlib.t.mjs @@ -93,6 +93,10 @@ let inflateSync_tsuite = { { value: zlib.deflateRawSync('WAKA', {dictionary: Buffer.from('WAKA')}), exception: 'InternalError: failed to inflate the compressed data: invalid distance too far back' }, + + { value: zlib.deflateSync('WAKA WAKA WAKA', {dictionary: Buffer.from('WAKA')}), + raw: false, + exception: 'TypeError: failed to inflate, dictionary is required' }, ]}; run([ -- 2.47.3