CVE-2023-24807 (published 2023-02-16T18:15Z)

Undici is an HTTP/1.1 client for Node.js. Prior to version 5.19.1, the `Headers.set()` and `Headers.append()` methods are vulnerable to Regular Expression Denial of Service (ReDoS) attacks when untrusted values are passed into the functions. This is due to the inefficient regular expression used to normalize the values in the `headerValueNormalize()` utility function. This vulnerability was patched in v5.19.1. No known workarounds are available.

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/nodejs/undici
commit_details: repo_url: https://github.com/nodejs/undici
author: Rich Trott
author_date: 2023-02-13 03:23:21-08:00
msg: Merge pull request from GHSA-r6ch-mqf9-qc9w

Refs: https://hackerone.com/bugs?report_id=1784449

Co-authored-by: Matteo Collina <hello@matteocollina.com>
repository: repo_url: https://github.com/nodejs/undici
repo_name: nodejs/undici
description: An HTTP/1.1 client, written from scratch for Node.js
repo_language: JavaScript
owner: nodejs
file_changes: filename: headers.js
change_type: ModificationType.MODIFY
diff: @@ -24,10 +24,12 @@ function headerValueNormalize (potentialValue) {
   //  To normalize a byte sequence potentialValue, remove
   //  any leading and trailing HTTP whitespace bytes from
   //  potentialValue.
-  return potentialValue.replace(
-    /^[\r\n\t ]+|[\r\n\t ]+$/g,
-    ''
-  )
+
+  // Trimming the end with `.replace()` and a RegExp is typically subject to
+  // ReDoS. This is safer and faster.
+  let i = potentialValue.length
+  while (/[\r\n\t ]/.test(potentialValue.charAt(--i)));
+  return potentialValue.slice(0, i + 1).replace(/^[\r\n\t ]+/, '')
 }
 
 function fill (headers, object) {

programming_language: JavaScript
filename: headers.js
change_type: ModificationType.MODIFY
diff: @@ -666,6 +666,18 @@ tap.test('invalid headers', (t) => {
   t.end()
 })
 
+tap.test('headers that might cause a ReDoS', (t) => {
+  t.doesNotThrow(() => {
+    // This test will time out if the ReDoS attack is successful.
+    const headers = new Headers()
+    const attack = 'a' + '\t'.repeat(500_000) + '\ta'
+    headers.append('fhqwhgads', attack)
+  })
+
+  t.end()
+})
+
+
 tap.test('Headers.prototype.getSetCookie', (t) => {
   t.test('Mutating the returned list does not affect the set-cookie list', (t) => {
     const h = new Headers([
@@ -682,4 +694,4 @@ tap.test('Headers.prototype.getSetCookie', (t) => {
   })
 
   t.end()
-})
+})
\ No newline at end of file

programming_language: JavaScript