Find regular expressions vulnerable to catastrophic backtracking (ReDoS) in Python code.
Project description
redos
Find regular expressions vulnerable to catastrophic backtracking (ReDoS) — fast, static, and dependency-free.
A single innocent-looking regex like (\w+)+$ can take exponential time on a
crafted input — long enough to freeze a request handler and take a service down.
redos finds those patterns without importing or running your code: it parses
your source with the standard-library ast module, then inspects the parsed
structure of every literal regex for the constructs that cause catastrophic
backtracking.
It has zero runtime dependencies, runs in CI (non-zero exit on findings), and is tuned for a low false-positive rate — patterns that Python's own regex engine rewrites into a safe, linear form are deliberately left alone.
Demo
The
examples/sampleproject contains two vulnerable regexes so you can try it immediately:redos examples/sample.
Installation
pip install redos
Or run from a checkout without installing:
PYTHONPATH=src python -m redos path/to/project
Usage
# Scan the current directory
redos .
# Scan a specific file or package
redos path/to/your_package
# Machine-readable output for tooling
redos . --format json
# Skip directories (repeatable); common ones are skipped by default
redos . --exclude examples --no-fail
Example
$ redos examples/sample
Scanned 3 regular-expression patterns. Found 2 possible ReDoS risks:
examples/sample/validators.py:9 re.compile(...)
pattern: ^(\w+)+$
[high] Nested quantifier: a repeated group that itself repeats (such as (a+)+) can backtrack exponentially.
examples/sample/validators.py:12 re.compile(...)
pattern: ^(a|a)+$
[high] Ambiguous alternation under a repeat: two branches can match the same text, which can backtrack exponentially.
Exit codes
| Code | Meaning |
|---|---|
0 |
No risky patterns found |
1 |
One or more risky patterns found |
2 |
Error (e.g. path not found) |
Pass --no-fail to always exit 0 (useful when you only want the report).
What it detects
redos reports two well-understood causes of catastrophic backtracking:
- Nested quantifiers — a repeated group that itself repeats, such as
(a+)+,(a*)*,([a-z]+)+, or(\w+)*. - Ambiguous alternation under a repeat — alternatives that can match the
same text inside a repeat, such as
(a|a)+, or a.branch like(.|a)*.
It analyses the regex after Python's parser applies its optimisations, so
patterns the engine makes safe — e.g. common-prefix factoring in (abc|abd)+,
or (\w|\d)+ collapsing to a single character class — are not flagged.
Only literal patterns passed to re (or regex) functions are analysed.
Patterns built from variables or expressions are skipped on purpose, so the tool
never guesses and never invents findings.
How it works
- Scan each
.pyfile withastand collect every literal pattern passed to a known regex function (re.compile,re.match,re.search, …). - Parse each pattern with the standard-library regular-expression parser to get its real structure (the same structure the engine executes).
- Inspect that structure for nested unbounded quantifiers and ambiguous alternation under a repeat, reporting each with its file, line, and reason.
Use it as a pre-commit hook
Add this to your project's .pre-commit-config.yaml and redos runs on every commit:
repos:
- repo: https://github.com/gazzycodes/redos
rev: v0.1.0
hooks:
- id: redos
Then pre-commit install once, or run it on demand with
pre-commit run redos --all-files.
Use it in CI (GitHub Actions)
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- run: pip install redos
- run: redos .
The non-zero exit on findings fails the job automatically.
Development
git clone https://github.com/gazzycodes/redos
cd redos
PYTHONPATH=src python -m unittest discover -s tests -v
Contributions are welcome — please open an issue or PR.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file redos-0.1.0.tar.gz.
File metadata
- Download URL: redos-0.1.0.tar.gz
- Upload date:
- Size: 64.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dfc76eb19c4711f9c8d29393cb996954f5579ec4ea6b1bb6c90629f6a55a8b5b
|
|
| MD5 |
ed98339837ded0f64674773f321c83ad
|
|
| BLAKE2b-256 |
e94e646debb4c529baf39aa256abb92ab7a76d97d8edf511959aaa9313a8bead
|
File details
Details for the file redos-0.1.0-py3-none-any.whl.
File metadata
- Download URL: redos-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58b559a305024195d35740f11a98acec9525a98d5a36ab0e32cc1e0e29d45369
|
|
| MD5 |
3fc9493c9cbf291a18e1f1b884cb1471
|
|
| BLAKE2b-256 |
ec9b94cf4688928f8b0cd3ec4d6babc5a41c78285a42c695e7df6da2001cb7e1
|