diff --git a/SPECS/nodejs24/CVE-2025-15504.patch b/SPECS/nodejs24/CVE-2025-15504.patch new file mode 100644 index 00000000000..8c46d03c583 --- /dev/null +++ b/SPECS/nodejs24/CVE-2025-15504.patch @@ -0,0 +1,29 @@ +From 1860997ed7f80ad2248526ae5cb82621024948cd Mon Sep 17 00:00:00 2001 +From: Romain Thomas +Date: Thu, 1 Jan 2026 12:50:49 +0100 +Subject: [PATCH] Fix #1277 + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/lief-project/LIEF/commit/8bba61609ff8dfd8046a67497bfa6e2d06f7d8d4.patch +--- + deps/LIEF/src/ELF/Parser.tcc | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/deps/LIEF/src/ELF/Parser.tcc b/deps/LIEF/src/ELF/Parser.tcc +index 03c2c5e7..88ca4bbd 100644 +--- a/deps/LIEF/src/ELF/Parser.tcc ++++ b/deps/LIEF/src/ELF/Parser.tcc +@@ -129,7 +129,9 @@ ok_error_t Parser::parse_binary() { + uint64_t offset = addr - seg->virtual_address(); + strm->setpos(offset); + binary_->gnu_hash_ = GnuHash::parse(*strm, dynsymcount); +- binary_->sizing_info_->gnu_hash = binary_->gnu_hash_->original_size(); ++ if (binary_->gnu_hash_ != nullptr) { ++ binary_->sizing_info_->gnu_hash = binary_->gnu_hash_->original_size(); ++ } + } + } + } +-- +2.45.4 + diff --git a/SPECS/nodejs24/CVE-2026-33671.patch b/SPECS/nodejs24/CVE-2026-33671.patch new file mode 100644 index 00000000000..a999a148807 --- /dev/null +++ b/SPECS/nodejs24/CVE-2026-33671.patch @@ -0,0 +1,356 @@ +From f720787b6ff1ad2479c9c9319a7baf844818de7d Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Mon, 13 Apr 2026 14:33:16 +0000 +Subject: [PATCH] Backport: picomatch safeguard against risky quantified + extglobs; add DEFAULT_MAX_EXTGLOB_RECURSION and analyze repeated extglobs in + parse to literalize or simplify where necessary + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/micromatch/picomatch/commit/5eceecd27543b8e056b9307d69e105ea03618a7d.patch +--- + .../node_modules/picomatch/lib/constants.js | 1 + + .../node_modules/picomatch/lib/parse.js | 302 ++++++++++++++++++ + 2 files changed, 303 insertions(+) + +diff --git a/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js b/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js +index 2bdb5a07..738c745a 100644 +--- a/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js ++++ b/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js +@@ -87,6 +87,7 @@ const POSIX_REGEX_SOURCE = { + }; + + module.exports = { ++ DEFAULT_MAX_EXTGLOB_RECURSION: 0, + MAX_LENGTH: 1024 * 64, + POSIX_REGEX_SOURCE, + +diff --git a/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/parse.js b/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/parse.js +index 8fd8ff49..8c087b3f 100644 +--- a/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/parse.js ++++ b/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/parse.js +@@ -45,6 +45,278 @@ const syntaxError = (type, char) => { + return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; + }; + ++const splitTopLevel = input => { ++ const parts = []; ++ let bracket = 0; ++ let paren = 0; ++ let quote = 0; ++ let value = ''; ++ let escaped = false; ++ ++ for (const ch of input) { ++ if (escaped === true) { ++ value += ch; ++ escaped = false; ++ continue; ++ } ++ ++ if (ch === '\\') { ++ value += ch; ++ escaped = true; ++ continue; ++ } ++ ++ if (ch === '"') { ++ quote = quote === 1 ? 0 : 1; ++ value += ch; ++ continue; ++ } ++ ++ if (quote === 0) { ++ if (ch === '[') { ++ bracket++; ++ } else if (ch === ']' && bracket > 0) { ++ bracket--; ++ } else if (bracket === 0) { ++ if (ch === '(') { ++ paren++; ++ } else if (ch === ')' && paren > 0) { ++ paren--; ++ } else if (ch === '|' && paren === 0) { ++ parts.push(value); ++ value = ''; ++ continue; ++ } ++ } ++ } ++ ++ value += ch; ++ } ++ ++ parts.push(value); ++ return parts; ++}; ++ ++const isPlainBranch = branch => { ++ let escaped = false; ++ ++ for (const ch of branch) { ++ if (escaped === true) { ++ escaped = false; ++ continue; ++ } ++ ++ if (ch === '\\') { ++ escaped = true; ++ continue; ++ } ++ ++ if (/[?*+@!()[\]{}]/.test(ch)) { ++ return false; ++ } ++ } ++ ++ return true; ++}; ++ ++const normalizeSimpleBranch = branch => { ++ let value = branch.trim(); ++ let changed = true; ++ ++ while (changed === true) { ++ changed = false; ++ ++ if (/^@\([^\\()[\]{}|]+\)$/.test(value)) { ++ value = value.slice(2, -1); ++ changed = true; ++ } ++ } ++ ++ if (!isPlainBranch(value)) { ++ return; ++ } ++ ++ return value.replace(/\\(.)/g, '$1'); ++}; ++ ++const hasRepeatedCharPrefixOverlap = branches => { ++ const values = branches.map(normalizeSimpleBranch).filter(Boolean); ++ ++ for (let i = 0; i < values.length; i++) { ++ for (let j = i + 1; j < values.length; j++) { ++ const a = values[i]; ++ const b = values[j]; ++ const char = a[0]; ++ ++ if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) { ++ continue; ++ } ++ ++ if (a === b || a.startsWith(b) || b.startsWith(a)) { ++ return true; ++ } ++ } ++ } ++ ++ return false; ++}; ++ ++const parseRepeatedExtglob = (pattern, requireEnd = true) => { ++ if ((pattern[0] !== '+' && pattern[0] !== '*') || pattern[1] !== '(') { ++ return; ++ } ++ ++ let bracket = 0; ++ let paren = 0; ++ let quote = 0; ++ let escaped = false; ++ ++ for (let i = 1; i < pattern.length; i++) { ++ const ch = pattern[i]; ++ ++ if (escaped === true) { ++ escaped = false; ++ continue; ++ } ++ ++ if (ch === '\\') { ++ escaped = true; ++ continue; ++ } ++ ++ if (ch === '"') { ++ quote = quote === 1 ? 0 : 1; ++ continue; ++ } ++ ++ if (quote === 1) { ++ continue; ++ } ++ ++ if (ch === '[') { ++ bracket++; ++ continue; ++ } ++ ++ if (ch === ']' && bracket > 0) { ++ bracket--; ++ continue; ++ } ++ ++ if (bracket > 0) { ++ continue; ++ } ++ ++ if (ch === '(') { ++ paren++; ++ continue; ++ } ++ ++ if (ch === ')') { ++ paren--; ++ ++ if (paren === 0) { ++ if (requireEnd === true && i !== pattern.length - 1) { ++ return; ++ } ++ ++ return { ++ type: pattern[0], ++ body: pattern.slice(2, i), ++ end: i ++ }; ++ } ++ } ++ } ++}; ++ ++const getStarExtglobSequenceOutput = pattern => { ++ let index = 0; ++ const chars = []; ++ ++ while (index < pattern.length) { ++ const match = parseRepeatedExtglob(pattern.slice(index), false); ++ ++ if (!match || match.type !== '*') { ++ return; ++ } ++ ++ const branches = splitTopLevel(match.body).map(branch => branch.trim()); ++ if (branches.length !== 1) { ++ return; ++ } ++ ++ const branch = normalizeSimpleBranch(branches[0]); ++ if (!branch || branch.length !== 1) { ++ return; ++ } ++ ++ chars.push(branch); ++ index += match.end + 1; ++ } ++ ++ if (chars.length < 1) { ++ return; ++ } ++ ++ const source = chars.length === 1 ++ ? utils.escapeRegex(chars[0]) ++ : `[${chars.map(ch => utils.escapeRegex(ch)).join('')}]`; ++ ++ return `${source}*`; ++}; ++ ++const repeatedExtglobRecursion = pattern => { ++ let depth = 0; ++ let value = pattern.trim(); ++ let match = parseRepeatedExtglob(value); ++ ++ while (match) { ++ depth++; ++ value = match.body.trim(); ++ match = parseRepeatedExtglob(value); ++ } ++ ++ return depth; ++}; ++ ++const analyzeRepeatedExtglob = (body, options) => { ++ if (options.maxExtglobRecursion === false) { ++ return { risky: false }; ++ } ++ ++ const max = ++ typeof options.maxExtglobRecursion === 'number' ++ ? options.maxExtglobRecursion ++ : constants.DEFAULT_MAX_EXTGLOB_RECURSION; ++ ++ const branches = splitTopLevel(body).map(branch => branch.trim()); ++ ++ if (branches.length > 1) { ++ if ( ++ branches.some(branch => branch === '') || ++ branches.some(branch => /^[*?]+$/.test(branch)) || ++ hasRepeatedCharPrefixOverlap(branches) ++ ) { ++ return { risky: true }; ++ } ++ } ++ ++ for (const branch of branches) { ++ const safeOutput = getStarExtglobSequenceOutput(branch); ++ if (safeOutput) { ++ return { risky: true, safeOutput }; ++ } ++ ++ if (repeatedExtglobRecursion(branch) > max) { ++ return { risky: true }; ++ } ++ } ++ ++ return { risky: false }; ++}; ++ ++ + /** + * Parse the given input string. + * @param {String} input +@@ -225,6 +497,8 @@ const parse = (input, options) => { + token.prev = prev; + token.parens = state.parens; + token.output = state.output; ++ token.startIndex = state.index; ++ token.tokensIndex = tokens.length; + const output = (opts.capture ? '(' : '') + token.open; + + increment('parens'); +@@ -234,6 +508,34 @@ const parse = (input, options) => { + }; + + const extglobClose = token => { ++ const literal = input.slice(token.startIndex, state.index + 1); ++ const body = input.slice(token.startIndex + 2, state.index); ++ const analysis = analyzeRepeatedExtglob(body, opts); ++ ++ if ((token.type === 'plus' || token.type === 'star') && analysis.risky) { ++ const safeOutput = analysis.safeOutput ++ ? (token.output ? '' : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) ++ : undefined; ++ const open = tokens[token.tokensIndex]; ++ ++ open.type = 'text'; ++ open.value = literal; ++ open.output = safeOutput || utils.escapeRegex(literal); ++ ++ for (let i = token.tokensIndex + 1; i < tokens.length; i++) { ++ tokens[i].value = ''; ++ tokens[i].output = ''; ++ delete tokens[i].suffix; ++ } ++ ++ state.output = token.output + open.output; ++ state.backtrack = true; ++ ++ push({ type: 'paren', extglob: true, value, output: '' }); ++ decrement('parens'); ++ return; ++ } ++ + let output = token.close + (opts.capture ? ')' : ''); + let rest; + +-- +2.45.4 + diff --git a/SPECS/nodejs24/CVE-2026-33672.patch b/SPECS/nodejs24/CVE-2026-33672.patch new file mode 100644 index 00000000000..8416dc78709 --- /dev/null +++ b/SPECS/nodejs24/CVE-2026-33672.patch @@ -0,0 +1,27 @@ +From 1a67b91ced4ac0d7c90ff429f7cee28ca9c7f038 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Mon, 13 Apr 2026 14:27:43 +0000 +Subject: [PATCH] Backport: add __proto__: null to POSIX_REGEX_SOURCE in + picomatch constants to prevent prototype pollution (from original.patch) + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/micromatch/picomatch/commit/4516eb521f13a46b2fe1a1d2c9ef6b20ddc0e903.patch +--- + .../tinyglobby/node_modules/picomatch/lib/constants.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js b/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js +index 3f7ef7e5..2bdb5a07 100644 +--- a/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js ++++ b/deps/npm/node_modules/tinyglobby/node_modules/picomatch/lib/constants.js +@@ -69,6 +69,7 @@ const WINDOWS_CHARS = { + */ + + const POSIX_REGEX_SOURCE = { ++ __proto__: null, + alnum: 'a-zA-Z0-9', + alpha: 'a-zA-Z', + ascii: '\\x00-\\x7F', +-- +2.45.4 + diff --git a/SPECS/nodejs24/nodejs24.spec b/SPECS/nodejs24/nodejs24.spec index d96d4185bd5..6211bdb6dc2 100644 --- a/SPECS/nodejs24/nodejs24.spec +++ b/SPECS/nodejs24/nodejs24.spec @@ -16,7 +16,7 @@ Name: nodejs24 # 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: 24.14.1 -Release: 1%{?dist} +Release: 2%{?dist} License: BSD AND MIT AND Public Domain AND NAIST-2003 AND Artistic-2.0 Vendor: Microsoft Corporation Distribution: Azure Linux @@ -35,6 +35,9 @@ Patch2: CVE-2024-22195.patch Patch3: CVE-2020-28493.patch Patch4: CVE-2024-34064.patch Patch5: CVE-2025-27516.patch +Patch6: CVE-2025-15504.patch +Patch7: CVE-2026-33671.patch +Patch8: CVE-2026-33672.patch BuildRequires: brotli-devel BuildRequires: c-ares-devel BuildRequires: coreutils >= 8.22 @@ -180,6 +183,9 @@ make cctest %{_prefix}/lib/node_modules/* %changelog +* Mon Apr 13 2026 Azure Linux Security Servicing Account - 24.14.1-2 +- Patch for CVE-2026-33672, CVE-2026-33671, CVE-2025-15504 + * Wed Apr 01 2026 Ratiranjan Behera - 24.14.1-1 - Upgrade to 24.14.1 - Security fixes included: