CVE-2021-27291 (published 2021-03-17T13:15Z)

In pygments 1.1+, fixed in 2.7.4, the lexers used to parse programming languages rely heavily on regular expressions. Some of the regular expressions have exponential or cubic worst-case complexity and are vulnerable to ReDoS. By crafting malicious input, an attacker can cause a denial of service.

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/pygments/pygments
commit_details: repo_url: https://github.com/pygments/pygments
author: Georg Brandl
author_date: 2021-01-11 09:46:34+01:00
msg: Fix several exponential/cubic complexity regexes found by Ben Caller/Doyensec
repository: repo_url: https://github.com/pygments/pygments
repo_name: pygments/pygments
description: Pygments is a generic syntax highlighter written in Python
repo_language: Python
owner: pygments
file_changes: filename: CHANGES
change_type: ModificationType.MODIFY
diff: @@ -38,8 +38,11 @@ Version 2.7.4
 - Limit recursion with nesting Ruby heredocs (#1638)
 - Fix a few inefficient regexes for guessing lexers
 - Fix the raw token lexer handling of Unicode (#1616)
-- Revert a private API change in the HTML formatter (#1655) -- please note that private APIs remain subject to change!
+- Revert a private API change in the HTML formatter (#1655) -- 
+  please note that private APIs remain subject to change!
 - Add Dracula theme style (#1636)
+- Fix several exponential/cubic-complexity regexes found by
+  Ben Caller/Doyensec (#1675)
 
 Thanks to Google's OSS-Fuzz project for finding many of these bugs.
 

programming_language: Markdown
filename: archetype.py
change_type: ModificationType.MODIFY
diff: @@ -58,7 +58,7 @@ class AtomsLexer(RegexLexer):
             (r'P((\d*(\.\d+)?[YyMmWwDd]){1,3}(T(\d*(\.\d+)?[HhMmSs]){,3})?|'
              r'T(\d*(\.\d+)?[HhMmSs]){,3})', Literal.Date),
             (r'[+-]?(\d+\.\d*|\.\d+|\d+)[eE][+-]?\d+', Number.Float),
-            (r'[+-]?(\d+)*\.\d+%?', Number.Float),
+            (r'[+-]?\d*\.\d+%?', Number.Float),
             (r'0x[0-9a-fA-F]+', Number.Hex),
             (r'[+-]?\d+%?', Number.Integer),
         ],

programming_language: Python
filename: factor.py
change_type: ModificationType.MODIFY
diff: @@ -265,7 +265,7 @@ class FactorLexer(RegexLexer):
             (r'(?:<PRIVATE|PRIVATE>)\s', Keyword.Namespace),
 
             # strings
-            (r'"""\s+(?:.|\n)*?\s+"""', String),
+            (r'"""\s(?:.|\n)*?\s"""', String),
             (r'"(?:\\\\|\\"|[^"])*"', String),
             (r'\S+"\s+(?:\\\\|\\"|[^"])*"', String),
             (r'CHAR:\s+(?:\\[\\abfnrstv]|[^\\]\S*)\s', String.Char),
@@ -322,7 +322,7 @@ class FactorLexer(RegexLexer):
         'slots': [
             (r'\s+', Text),
             (r';\s', Keyword, '#pop'),
-            (r'(\{\s+)(\S+)(\s+[^}]+\s+\}\s)',
+            (r'(\{\s+)(\S+)(\s[^}]+\s\}\s)',
              bygroups(Text, Name.Variable, Text)),
             (r'\S+', Name.Variable),
         ],

programming_language: Python
filename: jvm.py
change_type: ModificationType.MODIFY
diff: @@ -981,7 +981,6 @@ class CeylonLexer(RegexLexer):
             (r'(import)(\s+)', bygroups(Keyword.Namespace, Text), 'import'),
             (r'"(\\\\|\\[^\\]|[^"\\])*"', String),
             (r"'\\.'|'[^\\]'|'\\\{#[0-9a-fA-F]{4}\}'", String.Char),
-            (r'".*``.*``.*"', String.Interpol),
             (r'(\.)([a-z_]\w*)',
              bygroups(Operator, Name.Attribute)),
             (r'[a-zA-Z_]\w*:', Name.Label),

programming_language: Python
filename: matlab.py
change_type: ModificationType.MODIFY
diff: @@ -137,7 +137,7 @@ class MatlabLexer(RegexLexer):
             (r'.', Comment.Multiline),
         ],
         'deffunc': [
-            (r'(\s*)(?:(.+)(\s*)(=)(\s*))?(.+)(\()(.*)(\))(\s*)',
+            (r'(\s*)(?:(\S+)(\s*)(=)(\s*))?(.+)(\()(.*)(\))(\s*)',
              bygroups(Whitespace, Text, Whitespace, Punctuation,
                       Whitespace, Name.Function, Punctuation, Text,
                       Punctuation, Whitespace), '#pop'),
@@ -638,7 +638,7 @@ class OctaveLexer(RegexLexer):
             (r"[^']*'", String, '#pop'),
         ],
         'deffunc': [
-            (r'(\s*)(?:(.+)(\s*)(=)(\s*))?(.+)(\()(.*)(\))(\s*)',
+            (r'(\s*)(?:(\S+)(\s*)(=)(\s*))?(.+)(\()(.*)(\))(\s*)',
              bygroups(Whitespace, Text, Whitespace, Punctuation,
                       Whitespace, Name.Function, Punctuation, Text,
                       Punctuation, Whitespace), '#pop'),
@@ -710,7 +710,7 @@ class ScilabLexer(RegexLexer):
             (r'.', String, '#pop'),
         ],
         'deffunc': [
-            (r'(\s*)(?:(.+)(\s*)(=)(\s*))?(.+)(\()(.*)(\))(\s*)',
+            (r'(\s*)(?:(\S+)(\s*)(=)(\s*))?(.+)(\()(.*)(\))(\s*)',
              bygroups(Whitespace, Text, Whitespace, Punctuation,
                       Whitespace, Name.Function, Punctuation, Text,
                       Punctuation, Whitespace), '#pop'),

programming_language: Python
filename: objective.py
change_type: ModificationType.MODIFY
diff: @@ -261,11 +261,11 @@ class LogosLexer(ObjectiveCppLexer):
              'logos_classname'),
             (r'(%hook|%group)(\s+)([a-zA-Z$_][\w$]+)',
              bygroups(Keyword, Text, Name.Class)),
-            (r'(%config)(\s*\(\s*)(\w+)(\s*=\s*)(.*?)(\s*\)\s*)',
+            (r'(%config)(\s*\(\s*)(\w+)(\s*=)(.*?)(\)\s*)',
              bygroups(Keyword, Text, Name.Variable, Text, String, Text)),
             (r'(%ctor)(\s*)(\{)', bygroups(Keyword, Text, Punctuation),
              'function'),
-            (r'(%new)(\s*)(\()(\s*.*?\s*)(\))',
+            (r'(%new)(\s*)(\()(.*?)(\))',
              bygroups(Keyword, Text, Keyword, String, Keyword)),
             (r'(\s*)(%end)(\s*)', bygroups(Text, Keyword, Text)),
             inherit,

programming_language: Python
filename: templates.py
change_type: ModificationType.MODIFY
diff: @@ -1405,7 +1405,7 @@ class EvoqueLexer(RegexLexer):
             # see doc for handling first name arg: /directives/evoque/
             # + minor inconsistency: the "name" in e.g. $overlay{name=site_base}
             # should be using(PythonLexer), not passed out as String
-            (r'(\$)(evoque|overlay)(\{(%)?)(\s*[#\w\-"\'.]+[^=,%}]+?)?'
+            (r'(\$)(evoque|overlay)(\{(%)?)(\s*[#\w\-"\'.]+)?'
              r'(.*?)((?(4)%)\})',
              bygroups(Punctuation, Name.Builtin, Punctuation, None,
                       String, using(PythonLexer), Punctuation)),

programming_language: Python
filename: varnish.py
change_type: ModificationType.MODIFY
diff: @@ -61,7 +61,7 @@ class VCLLexer(RegexLexer):
              bygroups(Name.Attribute, Operator, Name.Variable.Global, Punctuation)),
             (r'(\.probe)(\s*=\s*)(\{)',
              bygroups(Name.Attribute, Operator, Punctuation), 'probe'),
-            (r'(\.\w+\b)(\s*=\s*)([^;]*)(\s*;)',
+            (r'(\.\w+\b)(\s*=\s*)([^;\s]*)(\s*;)',
              bygroups(Name.Attribute, Operator, using(this), Punctuation)),
             (r'\{', Punctuation, '#push'),
             (r'\}', Punctuation, '#pop'),

programming_language: Python