Metadata-Version: 2.4
Name: redos
Version: 0.1.0
Summary: Find regular expressions vulnerable to catastrophic backtracking (ReDoS) in Python code.
Project-URL: Homepage, https://github.com/gazzycodes/redos
Project-URL: Repository, https://github.com/gazzycodes/redos
Project-URL: Issues, https://github.com/gazzycodes/redos/issues
Author: gazzycodes
License: MIT License
        
        Copyright (c) 2026 gazzycodes
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: backtracking,cli,redos,regex,security,static-analysis
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# redos

[![CI](https://github.com/gazzycodes/redos/actions/workflows/ci.yml/badge.svg)](https://github.com/gazzycodes/redos/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![PyPI](https://img.shields.io/pypi/v/redos.svg)](https://pypi.org/project/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

![redos flagging a vulnerable regex in the bundled example](https://raw.githubusercontent.com/gazzycodes/redos/main/docs/demo.gif)

> The [`examples/sample`](examples/sample) project contains two vulnerable
> regexes so you can try it immediately: `redos examples/sample`.

## Installation

```bash
pip install redos
```

Or run from a checkout without installing:

```bash
PYTHONPATH=src python -m redos path/to/project
```

## Usage

```bash
# 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

```text
$ 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

1. **Scan** each `.py` file with `ast` and collect every literal pattern passed
   to a known regex function (`re.compile`, `re.match`, `re.search`, …).
2. **Parse** each pattern with the standard-library regular-expression parser
   to get its real structure (the same structure the engine executes).
3. **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:

```yaml
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)

```yaml
- 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

```bash
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](LICENSE).
