Using regular expressions is security-sensitive. It has led in the past to the following vulnerabilities:
Evaluating regular expressions against input strings is potentially an extremely CPU-intensive task. Specially crafted regular expressions such as
(a+)+s
will take several seconds to evaluate the input string aaaaaaaaaaaaaaaaaaaaaaaaaaaaabs
. The problem is that with
every additional a
character added to the input, the time required to evaluate the regex doubles. However, the equivalent regular
expression, a+s
(without grouping) is efficiently evaluated in milliseconds and scales linearly with the input size.
Evaluating such regular expressions opens the door to Regular expression Denial of Service (ReDoS) attacks.
In the context of a web application, attackers can force the web server to spend all of its resources evaluating regular expressions thereby making
the service inaccessible to genuine users.
This rule flags any execution of a hardcoded regular expression which has at least 3 characters and at least two instances of any of the following
characters: *+{
.
Example: (a+)*
Ask Yourself Whether
- the executed regular expression is sensitive and a user can provide a string which will be analyzed by this regular expression.
- your regular expression engine performance decrease with specially crafted inputs and regular expressions.
There is a risk if you answered yes to any of those questions.
Recommended Secure Coding Practices
Check whether your regular expression engine (the algorithm executing your regular expression) has any known vulnerabilities. Search for
vulnerability reports mentioning the one engine you’re are using.
If the regular expression is vulnerable to ReDos attacks, mitigate the risk by using a "match timeout" to limit the time spent running the regular
expression.
Remember also that a ReDos attack is possible if a user-provided regular expression is executed. This rule won’t detect this kind of injection.
Sensitive Code Example
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Runtime.Serialization
Imports System.Text.RegularExpressions
Imports System.Web
Namespace N
Public Class RegularExpression
Private Sub Foo(ByVal pattern As String, ByVal options As RegexOptions, ByVal matchTimeout As TimeSpan,
ByVal input As String, ByVal replacement As String, ByVal evaluator As MatchEvaluator)
' All the following instantiations are Sensitive. Validate the regular expression and matched input.
Dim r As Regex = New System.Text.RegularExpressions.Regex("(a+)+b")
r = New System.Text.RegularExpressions.Regex("(a+)+b", options)
r = New System.Text.RegularExpressions.Regex("(a+)+b", options, matchTimeout)
' All the following static methods are Sensitive.
System.Text.RegularExpressions.Regex.IsMatch(input, "(a+)+b")
System.Text.RegularExpressions.Regex.IsMatch(input, "(a+)+b", options)
System.Text.RegularExpressions.Regex.IsMatch(input, "(a+)+b", options, matchTimeout)
System.Text.RegularExpressions.Regex.Match(input, "(a+)+b")
System.Text.RegularExpressions.Regex.Match(input, "(a+)+b", options)
System.Text.RegularExpressions.Regex.Match(input, "(a+)+b", options, matchTimeout)
System.Text.RegularExpressions.Regex.Matches(input, "(a+)+b")
System.Text.RegularExpressions.Regex.Matches(input, "(a+)+b", options)
System.Text.RegularExpressions.Regex.Matches(input, "(a+)+b", options, matchTimeout)
System.Text.RegularExpressions.Regex.Replace(input, "(a+)+b", evaluator)
System.Text.RegularExpressions.Regex.Replace(input, "(a+)+b", evaluator, options)
System.Text.RegularExpressions.Regex.Replace(input, "(a+)+b", evaluator, options, matchTimeout)
System.Text.RegularExpressions.Regex.Replace(input, "(a+)+b", replacement)
System.Text.RegularExpressions.Regex.Replace(input, "(a+)+b", replacement, options)
System.Text.RegularExpressions.Regex.Replace(input, "(a+)+b", replacement, options, matchTimeout)
System.Text.RegularExpressions.Regex.Split(input, "(a+)+b")
System.Text.RegularExpressions.Regex.Split(input, "(a+)+b", options)
System.Text.RegularExpressions.Regex.Split(input, "(a+)+b", options, matchTimeout)
End Sub
End Class
End Namespace
Exceptions
Some corner-case regular expressions will not raise an issue even though they might be vulnerable. For example: (a|aa)+
,
(a|a?)+
.
It is a good idea to test your regular expression if it has the same pattern on both side of a "|
".
See