Regular expressions give operators a powerful way to configure APIs and gateways. Written carelessly, they open the door to ReDoS (regular expression denial of service) attacks.
Search and text pattern matching are common tasks needed in many applications. Regular expressions are patterns describing the shape of a piece of text. They allow matching text in a simple, declarative way without programming.
Here is a pattern for an ID made of two capital letters, a dash and three digits:
[A-Z]{2}-[0-9]{3}
[A-Z]{2}-[0-9]{3}
It matches AB-123 and XY-007 but not AB123.
Web servers and API gateways often accept regular expressions in their configuration, so that administrators can set up input validations and replacements. They can improve security, but if misconfigured, they open the door to ReDoS attacks.
Checking text against a regular expression usually takes a fraction of a millisecond. Some patterns, however, can be tricked into trying a huge number of combinations before they give up. A ReDoS attack (Regular Expression Denial of Service, CWE-1333) sends such input so that one small request keeps a CPU core busy.
Here is a pattern that matches API paths like /articles/2026/10/redos/comments:
^/articles/(.*)/(.*)/(.*)/comments$^/articles/(.*)/(.*)/(.*)/comments$
For a normal path the answer comes back instantly. Now an attacker sends a path that consists of /articles/ and 2,000 slashes:
GET /articles///////////////////////////////////////////////// … (2,000 slashes)GET /articles///////////////////////////////////////////////// … (2,000 slashes)
There is no /comments at the end, so the pattern can never match. But before the engine can say so, it tries every way to divide the slashes among the three (.*) groups. A path of just 2 KB takes about 6 seconds to check. A few such requests are enough to occupy every CPU core.
The fix is easy: ^/articles/([^/]*)/([^/]*)/([^/]*)/comments$ says that a group must not contain a slash. Now there is only one way to split the path, and the same request is checked in less than 0.1 ms.
APIs have a huge attack surface for ReDoS. Many API frameworks and gateway features take a regular expression from your configuration and run it against data sent by clients: paths, headers, message bodies and parameter values.
| Location | Pattern | Description |
|---|---|---|
| Path | ^/products/.* | Routes all requests below /products/ to the product API |
| Query | ^[a-z]+(,[a-z]+)*$ | Validates a comma-separated list like ?fields=title,author |
| Header | ^Bearer [A-Za-z0-9._-]+$ | Checks that the Authorization header carries a bearer token |
| Cookie | ^[0-9a-f]{32}$ | Checks that a session ID consists of 32 hex digits |
A badly written expression can take seconds or minutes to process a single malicious request of a few kilobytes. An attacker who finds such an expression can tie up all CPU cores of a server with a handful of requests.
Most regular expression engines, including the one in the Java runtime, work with backtracking: when a match fails, they go back and try every other way the expression could have matched.
The regular expression is part of your configuration, so it is up to you to keep it safe!
OpenAPI's pattern keyword describes the format of strings. API frameworks and gateways that validate requests against an OpenAPI document run these patterns against parameters and values in JSON bodies for every request and response.
Linting tools such as Spectral and vacuum encourage API designers to add these patterns: their OWASP rules flag string properties and parameters that have no pattern, format or enum. That is the right advice, because restricted strings block injection and other attacks. At the same time, every pattern widens the attack surface for ReDoS.
With OpenAPI, the problem is especially big: the OpenAPI document of an API is usually public. An attacker does not have to guess. They can read every regular expression of the API, scan them for vulnerable ones, and send input that keeps the server busy.
Examples for regex patterns in OpenAPI:
properties:
productId:
type: string
pattern: ^[A-Z]{2}-[0-9]{3}$
zipCode:
type: string
pattern: ^[0-9]{5}$
email:
type: string
format: email # checked with a regular expression
properties:
productId:
type: string
pattern: ^[A-Z]{2}-[0-9]{3}$
zipCode:
type: string
pattern: ^[0-9]{5}$
email:
type: string
format: email # checked with a regular expression
The format keyword can hide a regular expression as well: many validators check format: email with one.
This does not mean you should avoid patterns in OpenAPI. They are still an important protection against injection and other attacks. Instead, write safe patterns. How to Prevent ReDoS in APIs and API Gateways shows which patterns are dangerous and how to rewrite them.
Most ReDoS problems come from a few dangerous patterns, such as overlapping wildcards and nested quantifiers, and are easy to fix. Read How to Prevent ReDoS in APIs and API Gateways for the patterns to avoid, rules for writing safe regular expressions, and defenses in API frameworks and gateways.
To see which features of Membrane API Gateway apply regular expressions, with safe example configurations for each, read ReDoS Protection in Membrane API Gateway.
For more API security topics, see the API security overview.