Safeguard
Application Security•

CWE-777 Regular Expression without Anchors: Validation Bypass

A regex allowlist that is not anchored only checks that a good string appears somewhere. See how CWE-777 lets bad input through and how to fix it.

Safeguard Security Team
3 min read

CWE-777 is a validation mistake with a one-character fix. A regular expression is used to decide whether input is safe, but it has no anchors. It confirms that a valid-looking piece exists somewhere in the input, not that the whole input is valid.

Any code that uses a regex as an allowlist is exposed: login forms, redirect checks, filename filters, domain checks.

How it happens

Without a start anchor and an end anchor, a match can sit anywhere in the string. Malicious or malformed data may come before or after the part that matched. MITRE puts it this way: the kind of bad data that gets through depends on the context and on which anchors were left out.

A vulnerable check in Python:

import re

def is_company_email(addr):
    return re.search(r"[a-z]+@example\.com", addr) is not None

is_company_email("attacker@evil.test,boss@example.com")  # True
is_company_email("x@example.com.evil.test")              # True

Both inputs pass because a valid fragment appears inside them.

The MITRE record cites CVE-2022-30034: the web UI of a Python RPC framework did not use regex anchors to validate user login emails. That could allow an OAuth bypass, which MITRE tags as a chain with CWE-1390.

What an attacker gains

The consequences in the record are bypass of a protection mechanism, along with possible impact on confidentiality, availability and access control. The exact outcome depends on what the regex was guarding. If it guarded a login, the attacker may get in. If it guarded a file path, the attacker may reach files they should not.

How to find it

  • Search for regex use in validation code, especially calls like search that match anywhere.
  • Read each pattern and ask whether it starts with a start anchor and ends with an end anchor.
  • Write tests with junk placed before and after a valid value. Every one should fail.

How to fix it

Anchor the pattern and use a full-match function:

EMAIL = re.compile(r"[a-z]+@example\.com")

def is_company_email(addr):
    return EMAIL.fullmatch(addr) is not None

In languages without a full-match call, add the start and end anchors yourself. Be careful with the end anchor in some engines: a dollar sign can match before a trailing newline, so check your language's rules or use the dedicated end-of-string anchor.

Better still, do not rely on regex alone for security decisions. Parse the email, URL or path with a real parser and compare the parsed parts against an allowlist.

Quick check

Is a pattern with only a start anchor safe?

No. Data after the matching part still gets through. You need both ends anchored, or a full-match function.

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.