From 3c58b3aa3b04c6a1587bae903f944b19b606cce4 Mon Sep 17 00:00:00 2001 From: David Bankier Date: Tue, 10 Feb 2026 17:31:18 +0200 Subject: [PATCH] Fix for GHSA-x5gf-qvw8-r2rm fix(config): replace vulnerable args regex split with safe tokenizer while preserving #6031-compatible parsing behavior --- lib/tools/Config.js | 77 ++++++++++++++++++++-- test/programmatic/json_validation.mocha.js | 45 +++++++++++++ 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/lib/tools/Config.js b/lib/tools/Config.js index a3da91c4ce..aa1a6d92ff 100644 --- a/lib/tools/Config.js +++ b/lib/tools/Config.js @@ -55,6 +55,76 @@ var Config = module.exports = { } }; +function tokenizePm2ConfigArrayString(input) { + var tokens = []; + var token = ''; + var quote = null; + var escape = false; + var stripQuoteDelimiters = false; + + function flush() { + if (token && token.trim()) { + tokens.push(token); + } + token = ''; + } + + function isWhitespace(ch) { + return ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r' || ch === '\f' || ch === '\v'; + } + + for (var i = 0; i < input.length; i++) { + var ch = input[i]; + + if (escape) { + token += ch; + escape = false; + continue; + } + + if (ch === '\\') { + token += ch; + escape = true; + continue; + } + + if (quote) { + if (ch === quote) { + if (!stripQuoteDelimiters) { + token += ch; + } + quote = null; + stripQuoteDelimiters = false; + continue; + } + token += ch; + continue; + } + + if (ch === '"' || ch === "'") { + // Keep legacy behavior: + // - standalone quoted token: "a b" -> a b + // - quoted value inside existing token: --k="a b" -> --k="a b" + stripQuoteDelimiters = token.length === 0; + quote = ch; + if (!stripQuoteDelimiters) { + token += ch; + } + continue; + } + + if (isWhitespace(ch)) { + flush(); + continue; + } + + token += ch; + } + + flush(); + return tokens; +} + /** * Filter / Alias options */ @@ -200,12 +270,7 @@ Config._valid = function(key, value, sch){ // If first type is Array, but current is String, try to split them. if(scht.length > 1 && type != scht[0] && type == '[object String]'){ if(scht[0] == '[object Array]') { - value = value.split(/([\w\-]+\="[^"]*")|([\w\-]+\='[^']*')|"([^"]*)"|'([^']*)'|\s/) - // unfortunately, js does not support lookahead RegExp (/(?