Skip to content

Regular Expression Injection

What does this mean ?

When working with untrusted input, be mindful of regex injection attacks. An attacker can use regex injection to maliciously modify a regular expression, to make the regex match unintended results, or to make the regex consume excessive CPU resulting in a Denial of Service attack.

What can happen ?

Most of the regular expression engines use backtracking to try all possible execution paths of the regular expression when evaluating an input, in some cases it can cause performance issues, called catastrophic backtracking situations. In the worst case, the complexity of the regular expression is exponential in the size of the input, this means that a small carefully-crafted input (like 20 chars) can trigger catastrophic backtracking and cause a denial of service of the application.

Recommendation

Always use a match timeout when using regular expressions. Avoid using regular expressions based on user input. Escape special characters from user input by calling System.Text.RegularExpressions.Regex.Escape or another method. Allow only non-special characters from user input.

Sample Code

Vulnerable :

using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;

namespace WebApplicationDotNetCore.Controllers
{
    public class RSPEC2631RegExpInjectionNoncompliantController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Validate(string regex, string input)
        {
            bool match = Regex.IsMatch(input, regex); // Noncompliant

            return Content("Valid? " + match);
        }
    }
}

Non Vulnerable :

using System;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;

namespace WebApplicationDotNetCore.Controllers
{
    public class RSPEC2631RegExpInjectionCompliantController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Validate(string regex, string input)
        {
            bool match = Regex.IsMatch(input, Regex.Escape(regex)); // Compliant

            return Content("Valid? " + match);
        }
    }
}

Vulnerable :

public boolean validate(javax.servlet.http.HttpServletRequest request) {
  String regex = request.getParameter("regex");
  String input = request.getParameter("input");

  input.matches(regex);  // Noncompliant
}

Non Vulnerable :

public boolean validate(javax.servlet.http.HttpServletRequest request) {
  String regex = request.getParameter("regex");
  String input = request.getParameter("input");

  input.matches(Pattern.quote(regex));  // Compliant : with Pattern.quote metacharacters or escape sequences will be given no special meaning
}

Vulnerable :

$regex = $_GET["regex"];
$input = $_GET["input"];

preg_grep($regex, $input); // Noncompliant

Non Vulnerable :

$regex = $_GET["regex"];
$input = $_GET["input"];

preg_grep(preg_quote($regex), $input); // Compliant

References