CVE-2022-21680 (published 2022-01-14T17:15Z)

Marked is a markdown parser and compiler. Prior to version 4.0.10, the regular expression `block.def` may cause catastrophic backtracking against some strings and lead to a regular expression denial of service (ReDoS). Anyone who runs untrusted markdown through a vulnerable version of marked and does not use a worker with a time limit may be affected. This issue is patched in version 4.0.10. As a workaround, avoid running untrusted markdown through marked or run marked on a worker thread and set a reasonable time limit to prevent draining resources.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-1333
cwe_name: Inefficient Regular Expression Complexity
description: The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles.
extended_description: Some regular expression engines have a feature called "backtracking". If the token cannot match, the engine "backtracks" to a position that may result in a different token that can match.
                Backtracking becomes a weakness if all of these conditions are met:
                
                    The number of possible backtracking attempts are exponential relative to the length of the input.
                    The input can fail to match the regular expression.
                    The input can be long enough.
                
		
		  Attackers can create crafted inputs that
		  intentionally cause the regular expression to use
		  excessive backtracking in a way that causes the CPU
		  consumption to spike.
		
            
            

Fix information:
repo_url: https://github.com/markedjs/marked
commit_details: repo_url: https://github.com/markedjs/marked
author: Tony Brix
author_date: 2022-01-12 19:53:48-06:00
msg: Merge pull request from GHSA-rrrm-qjm4-v8hf

* fix: fix reflink redos

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

* fix: fix def redos

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

* fix block label for multiple slashes

Co-authored-by: MakeNowJust <make.just.on@gmail.com>
repository: repo_url: https://github.com/markedjs/marked
repo_name: markedjs/marked
description: A markdown parser and compiler. Built for speed.
repo_language: JavaScript
owner: markedjs
file_changes: filename: rules.js
change_type: ModificationType.MODIFY
diff: @@ -25,7 +25,7 @@ export const block = {
     + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
     + '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
     + ')',
-  def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
+  def: /^ {0,3}\[(label)\]: *(?:\n *)?<?([^\s>]+)>?(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,
   table: noopTest,
   lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
   // regex template, placeholders will be replaced according to different paragraph
@@ -34,7 +34,7 @@ export const block = {
   text: /^[^\n]+/
 };
 
-block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
+block._label = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
 block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
 block.def = edit(block.def)
   .replace('label', block._label)
@@ -162,8 +162,8 @@ export const inline = {
     + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
     + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>', // CDATA section
   link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
-  reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
-  nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
+  reflink: /^!?\[(label)\]\[(ref)\]/,
+  nolink: /^!?\[(ref)\](?:\[\])?/,
   reflinkSearch: 'reflink|nolink(?!\\()',
   emStrong: {
     lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
@@ -230,6 +230,11 @@ inline.link = edit(inline.link)
 
 inline.reflink = edit(inline.reflink)
   .replace('label', inline._label)
+  .replace('ref', block._label)
+  .getRegex();
+
+inline.nolink = edit(inline.nolink)
+  .replace('ref', block._label)
   .getRegex();
 
 inline.reflinkSearch = edit(inline.reflinkSearch, 'g')

programming_language: JavaScript
filename: cubic_def.cjs
change_type: ModificationType.ADD
diff: @@ -0,0 +1,4 @@
+module.exports = {
+  markdown: `[x]:${' '.repeat(1500)}x ${' '.repeat(1500)} x`,
+  html: `<p>[x]:${' '.repeat(1500)}x ${' '.repeat(1500)} x</p>`,
+};

programming_language: JavaScript
filename: reflink_redos.html
change_type: ModificationType.ADD
diff: @@ -0,0 +1 @@
+<p>[[]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([]([</p>

programming_language: Markdown
filename: reflink_redos.md
change_type: ModificationType.ADD
diff: @@ -0,0 +1,3 @@
+[x]: x
+
+[\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\](\[\]([

programming_language: Markdown