Safeguard
Application Security•

ASVS 5.0 V1.2.9: Escape Special Characters in Regex

ASVS V1.2.9 requires escaping regex metacharacters in user input used inside patterns. See built in escape functions and a test that catches the gap.

Safeguard Security Team
Updated 2 min read

ASVS 5.0 V1.2.9 (Level 2) requires that when untrusted text becomes part of a regular expression, its special characters are escaped (usually with a backslash) so they are read as literal characters and not as metacharacters. Search boxes and filter rules are the typical places this goes wrong.

Why it matters

A user who types .* into a search that is compiled as a pattern matches everything. A user who types (a+)+$ may freeze your server, and an unescaped [ can throw an exception that leaks a stack trace. Pattern based access rules can also be bypassed when a dot in example.com matches any character.

How to implement it

Use the standard library function every time, and prefer plain substring search when you do not need a pattern.

import re
pattern = re.compile(re.escape(user_text), re.IGNORECASE)
const escapeRegex = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const re = new RegExp(escapeRegex(userText), 'i');
Pattern p = Pattern.compile(Pattern.quote(userText), Pattern.CASE_INSENSITIVE);

In Go, use regexp.QuoteMeta. Anchor patterns with ^ and $ where whole value matching is intended.

How to test it

Search for ., *, (, [a- and a|b. Results must match only literal occurrences of those strings, and invalid ones must not raise errors. Grep for new RegExp( and re.compile( calls that include variables.

Common mistakes

  • Escaping once in the client and assuming the server did it.
  • Using a hand written escape that forgets the backslash itself.
  • Escaping then lowercasing in a way that alters the escapes.

Where this goes wrong in practice

A typical case is a URL allowlist implemented as a regex built from a configured domain: new RegExp(domain). Without escaping, the dots match any character, so exampleXcom passes, and without anchors, evil.example.com.attacker.net passes too. Escape the domain, anchor the pattern with ^ and $, and better yet parse the URL and compare the host exactly.

Search features are the second case. A user types c++ and the server returns a 500 error because the plus sign made an invalid pattern. That is a reliability bug first, and a denial of service vector when the pattern also causes heavy backtracking.

Quick check

When can you skip regex escaping altogether?

When a plain substring or equality check does the job. Then no pattern is built from user input.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.