Regular expression denial of service (ReDoS)

Regular expression denial of service (ReDoS)

Description

Building regular expressions directly from user-supplied patterns can let attackers choose expensive or inefficient expressions. Processing them may consume resources for a long time and disrupt the service.

Potential impact

  • Denial of service when an inefficient pattern slows or stalls the server
  • Poor responsiveness and instability for legitimate users

Remediation

  • Define patterns whose execution cost has been reviewed in code. Do not use user input directly as a pattern.
  • If dynamic selection is needed, choose from an allow-list of reviewed patterns and limit the length of the text being tested.
  • Use analysis tools such as recheck to support review. Defining a pattern as a constant does not by itself bound its execution cost.

Examples

Before

javascript
// Before
function search(text, pattern) {
  // Use user input directly as the regular expression pattern.
  const regex = new RegExp(pattern);
  return regex.test(text);
}

// Example usage
search("username", userInputPattern);

After

javascript
// After
function search(text) {
  // Use a fixed regular expression.
  const regex = /^\w+$/;
  return regex.test(text);
}

// Alternatively, restrict dynamic pattern selection.
function searchSafe(text, pattern) {
  // Use only allowed patterns from a predefined list.
  const allowedPatterns = ["^\\w+$", "^\\d{4,8}$"];
  if (!allowedPatterns.includes(pattern)) {
    throw new Error("허용되지 않은 패턴입니다.");
  }
  const regex = new RegExp(pattern);
  return regex.test(text);
}

Explanation:

  • Before: User input directly controls the pattern. Complex patterns may take excessive time and expose the service to denial of service.
  • After: A reviewed fixed pattern or allow-list prevents attackers from supplying their own expensive patterns.

References