Skip to main content

Insecure Use of Regular Expressions

Fixing Regular Expression Denial of Service (ReDoS)

About ReDos

What is Regular Expression Denial of Service (ReDos)?

Regular Expression Denial of Service (ReDos) is a type of attack that exploits regular expressions, which are patterns used to match and manipulate strings of text. This attack occurs when an application is forced to process a specially crafted input that causes the regular expression engine to enter a state of catastrophic backtracking.

Backtracking is a process used by the regular expression engine to match patterns that may have multiple valid interpretations. In a ReDos attack, an attacker uses a carefully crafted input string that triggers an excessive number of backtracking steps, leading to a denial of service (DoS) condition.

The attacker can use this to consume excessive amounts of CPU time, memory, or other system resources, making the application unresponsive or even causing it to crash.

Check out this video for a high-level explanation:

What is the impact of Regular Expression Denial of Service (ReDos)?

A successful ReDoS attack can have a significant impact depending on the system's resources and the attack's duration. Here are some potential impacts of ReDos attacks:

  • Denial of Service: The primary impact of a ReDos attack is a denial of service condition, which can cause the application to become unresponsive or crash. This can lead to system downtime, data loss, and reputational damage.
  • Resource consumption: ReDos attacks can consume excessive amounts of CPU time, memory, or other system resources, causing other applications on the system to slow down or crash.

How to prevent command injection?

Some measures that can help prevent ReDoS attacks are:

  • Input validation and sanitization: Ensure that user input is validated and sanitized before it is used to generate regular expressions. Use regular expressions or input filters to remove or encode any special characters that could be used to trigger backtracking.
  • Input length limits: Implement input length limits to restrict the length of user input that can be processed. This can help prevent the creation of regular expressions that are too complex and could trigger ReDos.
  • Timeout values: Use timeout values to limit the amount of time that can be spent on a single regular expression match. This can help prevent ReDos attacks by limiting the number of backtracking steps that can be taken.
  • Use secure libraries: Use up-to-date and secure regular expression libraries that are well-maintained and well-documented. This can help prevent the use of deprecated libraries that are no longer considered secure.
  • Regular security audits: Regularly audit your system and application for security vulnerabilities, including ReDos vulnerabilities. Use automated tools and manual testing to identify potential issues and fix them before they can be exploited.
  • Education and training: Educate your development team about the risks of ReDos attacks and the measures that can be taken to prevent them.

References

Taxonomies

Explanation & Prevention

Training

Option A: Make the Regex safe

  1. Go through the issues that GuardRails identified in the PR/MR.

  2. Take the highlighted regular expression and confirm that it is insecure at the recheck playground.

  3. Rewrite the regex to avoid the following patterns:

    • (a+)+: Nesting quantifiers (NQ)
    • (a|a)+: Quantified overlapping disjunctions (QOD)
    • \d+\d+: Quantified overlapping adjacencies (QAD)
  4. Verify that the improved regex works as intended and is no longer insecure.

  5. Ship it 🚢 and relax 🌴

Option B: Escape user input in regular expressions

  1. Go through the issues that GuardRails identified in the PR/MR.

  2. Verify that user input is used to create a regular expression.

  3. Create a function that escapes user input for use in regular expressions.

    RegExp.escape = function(str) {
    return String(str).replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
    };
  4. Use the created function to escape all user input.

    new RegExp(RegExp.escape(req.body.pattern));
  5. Test it and ensure the regular expression is still working as expected.

  6. Ship it 🚢 and relax 🌴

Fixing Regular Expression Injection

This rule detects Regular Expression injection vulnerability.

The vulnerability arises when the application does not properly sanitize user input used in regular expressions, and instead, the input is directly included in the regular expression pattern. An attacker can then craft input that alters the regular expression's behavior in unintended ways, leading to security vulnerabilities.

For example, an attacker may be able to inject special characters or modifiers into a regular expression to bypass input validation or extract sensitive information. They may also be able to use the regular expression to perform denial-of-service attacks, such as by causing excessive CPU or memory usage.

Option A: Use lodash library to escape the user input's regex string

To prevent regular expression injection attacks, you can escape all special characters in the regular expression string before using it.

  1. Identify the vulnerable patterns (example below):

    app.get("/search", (req, res) => {
    ...
    let str_regex = req.params["regex"]
    // highline-next-line
    let regex = new RegExp(str_regex)
    ...
    })
  2. Replace the vulnerable patterns (example below):

    // highline-next-line
    const escape_regex = require('lodash.escaperegexp')
    ...
    app.get("/search", (req, res) => {
    ...
    // highline-next-line
    let str_regex = escape_regex(req.params["regex"])
    let regex = new RegExp(str_regex)
    ...
    })
  3. Test it

  4. Ship it 🚢 and relax 🌴