html-minifier CVE-2022-37620
Regular Expression Denial of Service in html-minifier (reCustomIgnore).
The problem
html-minifier <= 4.0.0 (all published versions; the html-minifier-terser successor is also affected) is affected by
CVE-2022-37620 (CWE-1333 Inefficient Regular Expression Complexity (ReDoS)). The published package has
no fix available — exactly what npm audit reports. html-minifier's `minify()` replaces "ignored custom fragments" (template tags like `<%...%>` and `<?...?>`) via the `reCustomIgnore` regular expression `\s*(?:...)+\s*`. The leading `\s*` backtracks catastrophically: input containing a long run of whitespace not followed by a fragment makes `minify()` take time quadratic in the input length (a ~160 KB string takes ~40 seconds), so untrusted HTML can hang the event loop. Note: the widely-used successor `html-minifier-terser` ships the identical regex and is also affected; at the time of writing there is no fixed version of either on npm.
The fix — drop-in, no code changes
Add an overrides entry so every direct and transitive dependency on
html-minifier resolves to the patched fork, then reinstall:
{
"overrides": {
"html-minifier": "npm:@keep-lts/html-minifier@^4.0.1"
}
}
Equivalent for Yarn: use resolutions. The public API is unchanged — nothing else to do.
✓ Live on npm: @keep-lts/html-minifier · or install directly: npm i @keep-lts/html-minifier
What we changed
The leading `\s*` in `reCustomIgnore` is bounded to `\s{0,100}`. The trailing `\s*` is left unbounded because it only runs after a fragment has matched and therefore never backtracks. No real template has 100+ whitespace characters immediately before an ignored fragment, so minified output is byte-for-byte identical for realistic input — confirmed across 75 input/option combinations against the original. Matching is now linear (a 2 MB worst-case input completes in well under a second).
Proof of concept (the vulnerability)
const { minify } = require('html-minifier');
minify('x' + ' '.repeat(200000) + '!'); // hangs for many seconds on 4.0.0
@keep-lts/html-minifier@4.0.1How we keep it trustworthy
- Minimal, surgical patch — security only, no feature changes.
- A regression test that fails on the original and passes on the patch; legitimate behaviour preserved.
- Published under the
@keep-ltsorg with the full advisory and tests inside the package; upstream license & attribution retained.
Full advisory and changelog ship inside the package (SECURITY.md, CHANGELOG.md).