ReDoS Linter
A Python linter that detects Regular Expression Denial of Service (ReDoS) vulnerabilities in your code. ReDoS attacks occur when malicious input causes exponential backtracking in regular expressions, leading to denial of service.
Features
- Scans Python files for string literals that look like regular expressions
- Detects vulnerable regex patterns using the recheck engine
- Provides detailed attack vectors when vulnerabilities are found
- Supports both file and directory scanning
- Clean, colored output for better readability
- Support for ignore comments to exclude specific regexes from analysis
Installation
pip install redos-linter
Usage
Command Line
Check specific files or directories:
# Check a single file
redos-linter myfile.py
# Check multiple files
redos-linter file1.py file2.py
# Check a directory (recursively scans all .py files)
redos-linter src/
# Check multiple directories
redos-linter src/ tests/
Python Module
You can also run it as a Python module:
python -m redos_linter src/
Exit status
Both redos-linter and python -m redos_linter return:
0when every checked regex is safe, or no regexes are found.1when vulnerabilities are found, with locations, patterns, and source context in the output.2when the checker fails, returns an incomplete or invalid response, or cannot classify every regex.
Invalid arguments also return 2. File access and Python parsing errors terminate with a nonzero status.
Starting with version 0.3.2, findings fail the command; CI users who want an advisory check should configure their job to allow failure.
Output
The linter provides clear output indicating:
- ✅ Safe: No ReDoS vulnerabilities detected
- ❌ Vulnerable: ReDoS vulnerability found with attack vector details
When vulnerabilities are detected, the output includes:
- The vulnerable regular expression
- File location (line and column)
- Source code context
- Attack string that can trigger the ReDoS
- Pump strings for the attack
Examples of Vulnerable Patterns
import re
# Exponential backtracking due to nested quantifiers
vulnerable_1 = re.compile(r"^(a+)+$")
# Exponential backtracking due to overlapping quantifiers
vulnerable_2 = re.compile(r"(a|aa)+")
# Complex nested pattern
vulnerable_3 = re.compile(r"([a-z]+)+$")
# Real-world example
vulnerable_4 = re.compile(r"^(name|email|phone),([a-zA-Z0-9_]+,)*([a-zA-Z0-9_]+)$")
Examples of Safe Patterns
import re
# Simple safe regex
safe_1 = re.compile(r"^[a-zA-Z0-9_]+$")
# Email pattern (properly structured)
safe_2 = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
# Non-overlapping alternation
safe_3 = re.compile(r"^(cat|dog)$")
Ignoring Specific Regexes
You can exclude specific regexes from analysis by adding # redos-linter: ignore on the same line:
import re
# This vulnerable regex will be ignored
vulnerable = re.compile(r"(a+)+") # redos-linter: ignore
# This vulnerable regex will be detected
also_vulnerable = re.compile(r"([a-z]+)+$")
This is useful when:
- You've reviewed a regex and determined it's safe despite being flagged
- You want to temporarily ignore a warning while working on a fix
- You have a regex that's intentionally complex for a specific reason
Development
Install in development mode:
# Clone the repository
git clone <repository-url>
cd redos-linter
# Install in development mode
uv sync
# Run tests
uv run pytest
# Run linter on test file
uv run python -m redos_linter tests/test.py
Test Structure
The tests are organized as follows:
test_attack_string_limit.py- Tests for attack string length limitingtest_ignore_comments.py- Tests for ignore comments functionalitytest_integration.py- Integration tests for the command-line interfacetest_main_function.py- Tests for the main linter functionalitytest_regex_extractor.py- Tests for regex extraction from Python source codetest.py- Sample Python file with various regex patterns for testing
How It Works
- AST Analysis: Scans string literals containing regex metacharacters that form valid Python regex syntax, including patterns in assignments, containers, and nested calls. Direct literal pattern arguments to
reandregexAPIs (including imported aliases) are checked even when invalid, so malformed explicit patterns still fail. Literal membership comparisons, file modes, glob arguments, and subjects/replacements in recognized regex calls are treated as text. Message f-string fragments are skipped; fragments in explicit regex arguments and nested calls inside f-string expressions are still checked. - ReDoS Detection: Uses the recheck engine to analyze each potential regex for potential exponential backtracking. Leading global Python multiline (
(?m)) and dotall ((?s)) modes are translated to checker flags while reports retain the original pattern. Other unsupported syntax or flags still produce an unclassified result and exit status2; the linter does not evaluate dynamically constructed patterns. - Attack Generation: When vulnerabilities are found, generates specific attack strings that demonstrate the issue
- Reporting: Provides clear, actionable output with source context and attack vectors
Requirements
- Python 3.10+
- Deno runtime (automatically managed via the deno Python package)
Metadata
Release files for redos-linter 0.3.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| redos_linter-0.3.3.tar.gz | 757.4 kB | Without provenance | Details for redos_linter-0.3.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| redos_linter-0.3.3-py3-none-any.whl | Python 3 | none | any | Details for redos_linter-0.3.3-py3-none-any.whl |
Total release size: 1.5 MB
Release files / redos_linter-0.3.3.tar.gz
| Download URL | redos_linter-0.3.3.tar.gz |
|---|---|
| Size | 757.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d6cbf210edd6dc763beeb9a57ad77281e7a7af98453ba71656b75497ecd7b1cb
|
|
BLAKE2b-256 checksum How to use checksums |
14ce18190b1b67f1e71e7db479c06d1b97826ef8f511383ab4b56ba6dd3d4731
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / redos_linter-0.3.3-py3-none-any.whl
| Download URL | redos_linter-0.3.3-py3-none-any.whl |
|---|---|
| Size | 755.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0ddaef760afa56e1982522f7eda53c1c8e3b9cd65d80f4d510eaf5b14fcaa451
|
|
BLAKE2b-256 checksum How to use checksums |
1e1a011ce3f62336997454c029567cef88e386ee3cdf8fcaf3ec55e846abfd14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for redos-linter 0.3.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.