diff --git a/SPECS/nodejs/CVE-2026-21710.patch b/SPECS/nodejs/CVE-2026-21710.patch new file mode 100644 index 00000000000..5bc662d0c2a --- /dev/null +++ b/SPECS/nodejs/CVE-2026-21710.patch @@ -0,0 +1,152 @@ +From b046ea0fa85136ebb2a112360690650f827eb94c Mon Sep 17 00:00:00 2001 +From: Matteo Collina +Date: Thu, 19 Feb 2026 15:49:43 +0100 +Subject: [PATCH] http: use null prototype for headersDistinct/trailersDistinct + +Use { __proto__: null } instead of {} when initializing the +headersDistinct and trailersDistinct destination objects. + +A plain {} inherits from Object.prototype, so when a __proto__ +header is received, dest["__proto__"] resolves to Object.prototype +(truthy), causing _addHeaderLineDistinct to call .push() on it, +which throws an uncaught TypeError and crashes the process. + +Ref: https://hackerone.com/reports/3560402 +PR-URL: https://github.com/nodejs-private/node-private/pull/821 +Refs: https://hackerone.com/reports/3560402 +Reviewed-By: Marco Ippolito +Reviewed-By: Rafael Gonzaga +CVE-ID: CVE-2026-21710 +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/nodejs/node/commit/00ad47a28e.patch +--- + lib/_http_incoming.js | 4 +-- + .../test-http-headers-distinct-proto.js | 36 +++++++++++++++++++ + test/parallel/test-http-multiple-headers.js | 16 ++++----- + 3 files changed, 46 insertions(+), 10 deletions(-) + create mode 100644 test/parallel/test-http-headers-distinct-proto.js + +diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js +index e45ae819..77433e55 100644 +--- a/lib/_http_incoming.js ++++ b/lib/_http_incoming.js +@@ -131,7 +131,7 @@ ObjectDefineProperty(IncomingMessage.prototype, 'headersDistinct', { + __proto__: null, + get: function() { + if (!this[kHeadersDistinct]) { +- this[kHeadersDistinct] = {}; ++ this[kHeadersDistinct] = { __proto__: null }; + + const src = this.rawHeaders; + const dst = this[kHeadersDistinct]; +@@ -171,7 +171,7 @@ ObjectDefineProperty(IncomingMessage.prototype, 'trailersDistinct', { + __proto__: null, + get: function() { + if (!this[kTrailersDistinct]) { +- this[kTrailersDistinct] = {}; ++ this[kTrailersDistinct] = { __proto__: null }; + + const src = this.rawTrailers; + const dst = this[kTrailersDistinct]; +diff --git a/test/parallel/test-http-headers-distinct-proto.js b/test/parallel/test-http-headers-distinct-proto.js +new file mode 100644 +index 00000000..bd4cb82b +--- /dev/null ++++ b/test/parallel/test-http-headers-distinct-proto.js +@@ -0,0 +1,36 @@ ++'use strict'; ++ ++const common = require('../common'); ++const assert = require('assert'); ++const http = require('http'); ++const net = require('net'); ++ ++// Regression test: sending a __proto__ header must not crash the server ++// when accessing req.headersDistinct or req.trailersDistinct. ++ ++const server = http.createServer(common.mustCall((req, res) => { ++ const headers = req.headersDistinct; ++ assert.strictEqual(Object.getPrototypeOf(headers), null); ++ assert.deepStrictEqual(Object.getOwnPropertyDescriptor(headers, '__proto__').value, ['test']); ++ res.end(); ++})); ++ ++server.listen(0, common.mustCall(() => { ++ const port = server.address().port; ++ ++ const client = net.connect(port, common.mustCall(() => { ++ client.write( ++ 'GET / HTTP/1.1\r\n' + ++ 'Host: localhost\r\n' + ++ '__proto__: test\r\n' + ++ 'Connection: close\r\n' + ++ '\r\n', ++ ); ++ })); ++ ++ client.on('end', common.mustCall(() => { ++ server.close(); ++ })); ++ ++ client.resume(); ++})); +diff --git a/test/parallel/test-http-multiple-headers.js b/test/parallel/test-http-multiple-headers.js +index 1ebd290a..1188af5d 100644 +--- a/test/parallel/test-http-multiple-headers.js ++++ b/test/parallel/test-http-multiple-headers.js +@@ -27,13 +27,13 @@ const server = createServer( + host, + 'transfer-encoding': 'chunked' + }); +- assert.deepStrictEqual(req.headersDistinct, { ++ assert.deepStrictEqual(req.headersDistinct, Object.assign({ __proto__: null }, { + 'connection': ['close'], + 'x-req-a': ['eee', 'fff', 'ggg', 'hhh'], + 'x-req-b': ['iii; jjj; kkk; lll'], + 'host': [host], +- 'transfer-encoding': ['chunked'] +- }); ++ 'transfer-encoding': ['chunked'], ++ })); + + req.on('end', function() { + assert.deepStrictEqual(req.rawTrailers, [ +@@ -46,7 +46,7 @@ const server = createServer( + ); + assert.deepStrictEqual( + req.trailersDistinct, +- { 'x-req-x': ['xxx', 'yyy'], 'x-req-y': ['zzz; www'] } ++ Object.assign({ __proto__: null }, { 'x-req-x': ['xxx', 'yyy'], 'x-req-y': ['zzz; www'] }) + ); + + res.setHeader('X-Res-a', 'AAA'); +@@ -129,14 +129,14 @@ server.listen(0, common.mustCall(() => { + 'x-res-d': 'JJJ; KKK; LLL', + 'transfer-encoding': 'chunked' + }); +- assert.deepStrictEqual(res.headersDistinct, { ++ assert.deepStrictEqual(res.headersDistinct, Object.assign({ __proto__: null }, { + 'x-res-a': [ 'AAA', 'BBB', 'CCC' ], + 'x-res-b': [ 'DDD; EEE; FFF; GGG' ], + 'connection': [ 'close' ], + 'x-res-c': [ 'HHH', 'III' ], + 'x-res-d': [ 'JJJ; KKK; LLL' ], +- 'transfer-encoding': [ 'chunked' ] +- }); ++ 'transfer-encoding': [ 'chunked' ], ++ })); + + res.on('end', function() { + assert.deepStrictEqual(res.rawTrailers, [ +@@ -150,7 +150,7 @@ server.listen(0, common.mustCall(() => { + ); + assert.deepStrictEqual( + res.trailersDistinct, +- { 'x-res-x': ['XXX', 'YYY'], 'x-res-y': ['ZZZ; WWW'] } ++ Object.assign({ __proto__: null }, { 'x-res-x': ['XXX', 'YYY'], 'x-res-y': ['ZZZ; WWW'] }) + ); + server.close(); + }); +-- +2.45.4 + diff --git a/SPECS/nodejs/CVE-2026-33750.patch b/SPECS/nodejs/CVE-2026-33750.patch new file mode 100644 index 00000000000..b59475c42cd --- /dev/null +++ b/SPECS/nodejs/CVE-2026-33750.patch @@ -0,0 +1,32 @@ +From 62fac79ac5c1e3fa7806fa649e56e8b9991abd7b Mon Sep 17 00:00:00 2001 +From: Alec Fenichel +Date: Fri, 27 Mar 2026 04:40:32 -0400 +Subject: [PATCH] Backport fix for GHSA-f886-m6hf-6m8v to v2 (#96) + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/juliangruber/brace-expansion/commit/311ac0d54994158c0a384e286a7d6cbb17ee8ed5.patch +--- + deps/minimatch/src/node_modules/brace-expansion/index.js | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/deps/minimatch/src/node_modules/brace-expansion/index.js b/deps/minimatch/src/node_modules/brace-expansion/index.js +index a27f81ce..376d060c 100644 +--- a/deps/minimatch/src/node_modules/brace-expansion/index.js ++++ b/deps/minimatch/src/node_modules/brace-expansion/index.js +@@ -148,7 +148,7 @@ function expand(str, isTop) { + var y = numeric(n[1]); + var width = Math.max(n[0].length, n[1].length) + var incr = n.length == 3 +- ? Math.abs(numeric(n[2])) ++ ? Math.max(Math.abs(numeric(n[2])), 1) + : 1; + var test = lte; + var reverse = y < x; +@@ -200,4 +200,3 @@ function expand(str, isTop) { + + return expansions; + } +- +-- +2.45.4 + diff --git a/SPECS/nodejs/nodejs18.spec b/SPECS/nodejs/nodejs18.spec index 4813063a910..7b0901c1006 100644 --- a/SPECS/nodejs/nodejs18.spec +++ b/SPECS/nodejs/nodejs18.spec @@ -6,7 +6,7 @@ Name: nodejs18 # WARNINGS: MUST check and update the 'npm_version' macro for every version update of this package. # The version of NPM can be found inside the sources under 'deps/npm/package.json'. Version: 18.20.3 -Release: 12%{?dist} +Release: 13%{?dist} License: BSD and MIT and Public Domain and NAIST-2003 and Artistic-2.0 Group: Applications/System Vendor: Microsoft Corporation @@ -31,6 +31,8 @@ Patch11: CVE-2025-5889.patch Patch12: CVE-2025-5222.patch Patch13: CVE-2025-55131.patch Patch14: CVE-2026-27135.patch +Patch15: CVE-2026-21710.patch +Patch16: CVE-2026-33750.patch BuildRequires: brotli-devel BuildRequires: coreutils >= 8.22 BuildRequires: gcc @@ -131,6 +133,9 @@ make cctest %{_datadir}/systemtap/tapset/node.stp %changelog +* Thu Apr 02 2026 Azure Linux Security Servicing Account - 18.20.3-13 +- Patch for CVE-2026-33750, CVE-2026-21710 + * Fri Mar 20 2026 Azure Linux Security Servicing Account - 18.20.3-12 - Patch for CVE-2026-27135