CVE-2022-21670: Inefficient Regular Expression Complexity (CWE-1333)
value: markdown-it is a Markdown parser. Prior to version 1.3.2, special patterns with length greater than 50 thousand characterss could slow down the parser significantly. Users should upgrade to version 12.3.2 to receive a patch. There are no known workarounds aside from upgrading.
CWE description: The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles.
CVSS v3 base score: 5.3
Published: 2022-01-10T21:15Z
Repository: https://github.com/markdown-it/markdown-it
Language: JavaScript
Files changed: CHANGELOG.md, lib/rules_inline/newline.js, test/pathological.js
Commit date: 2022-01-08 18:00:47 +0300
Commit message: Fix possible ReDOS in newline rule.

Co-authored-by: MakeNowJust <make.just.on@gmail.com>

Diff: diff --git a/CHANGELOG.md b/CHANGELOG.md
index 31edd3a..0b74416 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,10 +3,14 @@
 All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [12.3.2] - 2022-01-08
+### Security
+- Fix possible ReDOS in newline rule. Thanks to @MakeNowJust.
+
 
 ## [12.3.1] - 2022-01-07
 ### Fixed
 - Fix corner case when tab prevents paragraph continuation in lists, #830.
 
@@ -586,10 +590,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - New project name & home! Now it's `markdown-it`,
 - Sugar for constructor call - `new` is not mandatory now.
 - Renamed presets folder (configs -> presets).
 
 
+[12.3.2]: https://github.com/markdown-it/markdown-it/compare/12.3.1...12.3.2
 [12.3.1]: https://github.com/markdown-it/markdown-it/compare/12.3.0...12.3.1
 [12.3.0]: https://github.com/markdown-it/markdown-it/compare/12.2.0...12.3.0
 [12.2.0]: https://github.com/markdown-it/markdown-it/compare/12.1.0...12.2.0
 [12.1.0]: https://github.com/markdown-it/markdown-it/compare/12.0.6...12.1.0
 [12.0.6]: https://github.com/markdown-it/markdown-it/compare/12.0.5...12.0.6
diff --git a/lib/rules_inline/newline.js b/lib/rules_inline/newline.js
index 14aa42d..9eeead4 100644
--- a/lib/rules_inline/newline.js
+++ b/lib/rules_inline/newline.js
@@ -4,11 +4,11 @@
 
 var isSpace = require('../common/utils').isSpace;
 
 
 module.exports = function newline(state, silent) {
-  var pmax, max, pos = state.pos;
+  var pmax, max, ws, pos = state.pos;
 
   if (state.src.charCodeAt(pos) !== 0x0A/* \n */) { return false; }
 
   pmax = state.pending.length - 1;
   max = state.posMax;
@@ -18,11 +18,15 @@ module.exports = function newline(state, silent) {
   // Pending string is stored in concat mode, indexed lookups will cause
   // convertion to flat mode.
   if (!silent) {
     if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {
       if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {
-        state.pending = state.pending.replace(/ +$/, '');
+        // Find whitespaces tail of pending chars.
+        ws = pmax - 1;
+        while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) ws--;
+
+        state.pending = state.pending.slice(0, ws);
         state.push('hardbreak', 'br', 0);
       } else {
         state.pending = state.pending.slice(0, -1);
         state.push('softbreak', 'br', 0);
       }
diff --git a/test/pathological.js b/test/pathological.js
index 8481efd..a64a10e 100644
--- a/test/pathological.js
+++ b/test/pathological.js
@@ -136,7 +136,11 @@ describe('Pathological sequences speed', () => {
     });
 
     it('autolinks <<<<...<<> pattern', async () => {
       await test_pattern('<'.repeat(400000) + '>');
     });
+
+    it('hardbreak whitespaces pattern', async () => {
+      await test_pattern('x' + ' '.repeat(150000) + 'x  \nx');
+    });
   });
 });

Vulnerable code:   var pmax, max, pos = state.pos;
        state.pending = state.pending.replace(/ +$/, '');
Fixed code: ## [12.3.2] - 2022-01-08
### Security
- Fix possible ReDOS in newline rule. Thanks to @MakeNowJust.

[12.3.2]: https://github.com/markdown-it/markdown-it/compare/12.3.1...12.3.2
  var pmax, max, ws, pos = state.pos;
        // Find whitespaces tail of pending chars.
        ws = pmax - 1;
        while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) ws--;

        state.pending = state.pending.slice(0, ws);

    it('hardbreak whitespaces pattern', async () => {
      await test_pattern('x' + ' '.repeat(150000) + 'x  \nx');
    });