ReDoctor - A Python ReDoS (Regular Expression Denial of Service) vulnerability checker
Project description
ReDoctor
The Python ReDoS Vulnerability Scanner — Protect your applications from Regular Expression Denial of Service attacks.
⚠️ License Notice: ReDoctor is licensed under the Business Source License 1.1 (BSL-1.1). Non-commercial use is free. Commercial production use requires a paid license. The code will convert to MIT license on January 9, 2031.
Quick Start • Features • Installation • Usage • Documentation • Contributing
🚨 What is ReDoS?
Regular Expression Denial of Service (ReDoS) is a type of algorithmic complexity attack that exploits the worst-case behavior of regex engines. A vulnerable regex can cause your application to hang for minutes or hours when processing malicious input.
# ⚠️ This innocent-looking regex is VULNERABLE!
import re
pattern = r"^(a+)+$"
# This will hang your application:
re.match(pattern, "a" * 30 + "!") # Takes exponential time!
ReDoctor detects these vulnerabilities before they reach production.
⚡ Quick Start
# Install
pip install redoctor
# Check a pattern from command line
redoctor '^(a+)+$'
# Output: VULNERABLE: ^(a+)+$ - Complexity: O(2^n)
# Use in Python
from redoctor import check
result = check(r"^(a+)+$")
if result.is_vulnerable:
print(f"🚨 Vulnerable! Complexity: {result.complexity}")
print(f" Attack string: {result.attack}")
✨ Features
🔬 Hybrid Analysis EngineCombines static automata-based analysis with intelligent fuzzing for comprehensive detection. Catches vulnerabilities that single-approach tools miss. ⚡ Fast & Zero DependenciesPure Python with no external dependencies. Runs in milliseconds for most patterns. Compatible with Python 3.6+. |
🎯 Accurate ResultsGenerates proof-of-concept attack strings with complexity analysis ( 🛡️ Source Code ScanningScan your entire Python codebase for vulnerable regex patterns. Integrates with CI/CD pipelines. |
📦 Installation
pip install redoctor
Requirements: Python 3.6+ Dependencies: None (pure Python)
🔧 Usage
Command Line Interface
# Check a single pattern
redoctor '^(a+)+$'
# Verbose output with attack details
redoctor '(a|a)*$' --verbose
# Check with flags
redoctor 'pattern' --ignore-case --multiline
# Read patterns from stdin
echo '^(a+)+$' | redoctor --stdin
# Set timeout
redoctor 'complex-pattern' --timeout 30
Exit codes:
0- Pattern is safe1- Pattern is vulnerable2- Error occurred
Python API
from redoctor import check, is_vulnerable, Config
# Simple check
result = check(r"^(a+)+$")
print(result.status) # Status.VULNERABLE
print(result.complexity) # O(2^n)
print(result.attack) # 'aaaaaaaaaaaaaaaaaaaaa!'
# Quick vulnerability check
if is_vulnerable(r"(x+x+)+y"):
print("Don't use this pattern!")
# Access attack pattern details
if result.is_vulnerable:
attack = result.attack_pattern
print(f"Prefix: {attack.prefix!r}")
print(f"Pump: {attack.pump!r}")
print(f"Suffix: {attack.suffix!r}")
# Generate attack strings of different lengths
short_attack = attack.build(10) # 10 pump repetitions
long_attack = attack.build(100) # 100 pump repetitions
# Custom configuration
config = Config(
timeout=30.0, # Analysis timeout in seconds
max_attack_length=4096, # Max attack string length
)
result = check(r"complex-pattern", config=config)
# Quick mode for CI/CD
config = Config.quick() # 1 second timeout
result = check(pattern, config=config)
Source Code Scanning
Scan your Python codebase for vulnerable regex patterns:
from redoctor.integrations import scan_file, scan_directory
# Scan a single file
vulnerabilities = scan_file("myapp/validators.py")
for vuln in vulnerabilities:
print(f"{vuln.file}:{vuln.line} - {vuln.pattern}")
print(f" Complexity: {vuln.diagnostics.complexity}")
# Scan entire directory
for vuln in scan_directory("src/", recursive=True):
if vuln.is_vulnerable:
print(f"🚨 {vuln}")
📊 Complexity Types
ReDoctor classifies vulnerabilities by their time complexity:
| Complexity | Description | Risk Level |
|---|---|---|
O(n) |
Linear - Safe | ✅ Safe |
O(n²) |
Quadratic | ⚠️ Moderate |
O(n³) |
Cubic | ⚠️ High |
O(2ⁿ) |
Exponential | 🚨 Critical |
🔍 How It Works
ReDoctor uses a hybrid approach combining two detection methods:
┌─────────────────────────────────────────────────────────────┐
│ ReDoctor Engine │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Automaton │ │ Fuzz │ │
│ │ Checker │ │ Checker │ │
│ │ │ │ │ │
│ │ • NFA analysis │ │ • VM execution │ │
│ │ • O(n) check │ │ • Step counting│ │
│ │ • Witness gen │ │ • Mutation │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ └───────────┬───────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Recall Validator│ │
│ │ (confirmation) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Diagnostics │ │
│ │ • Complexity │ │
│ │ • Attack string│ │
│ │ • Hotspot │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
- Automaton Checker: Builds an ε-NFA from the regex and analyzes for ambiguity patterns that cause backtracking.
- Fuzz Checker: Executes patterns in a step-counting VM with evolved test strings to detect polynomial/exponential growth.
- Recall Validator: Confirms detected vulnerabilities with real execution timing.
📚 Documentation
Full documentation is available at redoctor.getpagespeed.com
🧪 Examples of Vulnerable Patterns
from redoctor import check
# Classic nested quantifier - Exponential O(2^n)
check(r"^(a+)+$") # VULNERABLE
# Overlapping alternatives - Exponential O(2^n)
check(r"(a|a)*$") # VULNERABLE
# Polynomial O(n²)
check(r".*a.*a.*") # VULNERABLE
# Email-like pattern - Often vulnerable
check(r"^([a-zA-Z0-9]+)*@") # VULNERABLE
# Safe patterns
check(r"^[a-z]+$") # SAFE
check(r"^\d{1,10}$") # SAFE
check(r"^[A-Z][a-z]*$") # SAFE
🤝 Contributing
Contributions are welcome! See our Contributing Guide for details.
# Clone the repo
git clone https://github.com/GetPageSpeed/redoctor.git
cd redoctor
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -x --tb=short
# Run with coverage
make tests
📄 License
ReDoctor is licensed under the Business Source License 1.1 (BSL-1.1).
- ✅ Free for non-commercial and non-production use
- ✅ Free for personal projects, education, and research
- 💼 Commercial production use requires a paid license
- 🔓 Converts to MIT License on January 9, 2031
🙏 Acknowledgments
- Inspired by recheck and academic research on ReDoS detection
- Built with ❤️ by GetPageSpeed
Protect your applications from ReDoS attacks.
⭐ Star on GitHub •
📦 View on PyPI •
📚 Read the Docs
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 redoctor-0.1.1.tar.gz.
File metadata
- Download URL: redoctor-0.1.1.tar.gz
- Upload date:
- Size: 73.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
606ff556d103b843134ff02a32c61c22f64b78ec465c58a93d56a5a227983498
|
|
| MD5 |
de76c68cbf5f53d52d03da46e6438766
|
|
| BLAKE2b-256 |
017111bc5f27fc4db76ce644b3cf903a6524d734f1f3b9acb5553ba408c509c8
|
File details
Details for the file redoctor-0.1.1-py3-none-any.whl.
File metadata
- Download URL: redoctor-0.1.1-py3-none-any.whl
- Upload date:
- Size: 63.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
345ebee5064ac2926b186d9be3a07ce38babefa1f78c8f77bd9f014a62621661
|
|
| MD5 |
ec4ce4d5e49d33ae76094d2c16413608
|
|
| BLAKE2b-256 |
87492699e6e00a46b3474dbd09a9d99370afcdda9f9b2d29b6057117a34472de
|