fix(prettify): replace regex-based query parsing to avoid ReDoS
Checklist (per Contribution Guidelines) Target branch is master
Only source files are modified (st/prettify/run_prettify.js)
No build artifacts are committed (builds will be generated on release)
Local setup: npm i completed
Verified locally that the change works as expected
Background
In st/prettify/run_prettify.js, the query string was parsed via a global regex replace:
B.replace(/[?&]([^&=]+)=([^&]+)/g, function (g, r, x) {
x = decodeURIComponent(x);
r = decodeURIComponent(r);
r == "autorun" ? (U = !/^[0fn]/i.test(x))
: r == "lang" ? H.push(x)
: r == "skin" ? P.push(x)
: r == "callback" && M.push(x);
});
This pattern can suffer from catastrophic backtracking on crafted inputs (e.g. '?'.repeat(100000) + '=') and leads to a potential ReDoS risk if the query is attacker-controlled.
Solution
Replace the regex-based parsing with a linear, index-based split that preserves behavior but avoids backtracking:
B.split(/[?&]/).forEach(function (s) {
if (!s) return;
var i = s.indexOf('=');
if (i < 0 || i === s.length - 1) return; // ignore invalid / valueless pairs
var r = decodeURIComponent(s.slice(0, i));
var x = decodeURIComponent(s.slice(i + 1));
r == 'autorun' ? (U = !/^[0fn]/i.test(x))
: r == 'lang' ? H.push(x)
: r == 'skin' ? P.push(x)
: r == 'callback' && M.push(x);
});
Why safer: No backtracking hotspots; runtime grows linearly with input length. Behavior: Keys handled are unchanged (autorun, lang, skin, callback); invalid pairs are ignored just like before; decodeURIComponent preserved.
Screenshots
before:
after:
Type of change
Bug fix (non-breaking change which fixes an issue)
Notes
If the project prefers tests to be in its existing framework only, I can adjust or remove the accompanying regression test.