# Oralyzer fuzzes redirect parameters and reports only the payloads the server follows

> Oralyzer is a Python CLI that throws open redirect payloads at a URL, checks whether the response actually lands on an external host, and can do the same for header, JavaScript and meta tag redirects plus CRLF injection, with JSON export for triage.

**r0075h3ll/Oralyzer** — Python tool that probes websites for open redirection via headers, JavaScript, and meta-tag refresh, pulls candidate URLs from the Wayback Machine, and checks CRLF injection and DOM XSS.

- Repository: https://github.com/r0075h3ll/Oralyzer
- Stars: 831 · Forks: 115
- Language: Python
- License: GPL-3.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/r0075h3ll-oralyzer

## It reports redirects the server actually follows, not redirects it advertises

The core claim of Oralyzer is narrow and testable: it fuzzes the target URL with redirect payloads and reports which ones the server actually follows to an external host. That last clause is what separates it from a pattern match on a response body. A page containing window.location or a meta refresh is not a finding on its own; the finding is the server sending the client somewhere off-site.

Three redirect mechanisms are detected, and the README names them as header, JavaScript and meta-tag redirects. The header case is the classic one: the response carries a 302 whose Location points at an attacker controlled host, and the JSON export example shows exactly that shape with a request_url of https://example.com/login?next=//evil.com, a payload of //evil.com, a status_code of 302 and a destination of https://evil.com.

The JavaScript case is different in kind. There the status code is 200, and the finding carries a sources array listing the script sinks that were seen, with location.href and document.URL as the examples. A protocol relative payload such as //evil.com is what makes both the header and the JavaScript variants work, since the browser resolves it against the current scheme and host.

This is a scanner aimed at one vulnerability class. The topic list for the repository is crlf-injection, dom-xss, open-redirections and scanner, and the PyPI description mentions DOM XSS checks alongside the redirect work.

## CRLF injection and URL discovery are separate switches

Two capabilities sit alongside the redirect scanning, and both are opt-in because they change what the tool does to the target.

The CRLF option enables HTTP response splitting scanning, where injected carriage return and line feed sequences in a parameter can let an attacker add headers or a body to the server's response. The repository topic list includes crlf-injection, and the command line option table gives the flag as -crlf with the description Scan for CRLF injection.

URL discovery is the other one. The --discover flag harvests candidate URLs from Common Crawl's index for a given domain, which turns a single known URL into a set of paths worth probing. The repository description mentions pulling candidate URLs from the Wayback Machine, while the README documents Common Crawl as the source for --discover.

Both features change the blast radius of a run. Discovery multiplies the number of requests, and CRLF testing sends deliberately malformed input to the target. Neither is enabled by default, which is the right default for a tool that will point at production applications.

The remaining options are operational rather than exploratory: --proxy routes requests through an HTTP proxy, --timeout sets the request timeout with a default of 10 seconds, --workers sets concurrency with a default of 5, --limit stops after a number of findings, --filter narrows reporting to header, javascript, meta or crlf, and -p takes a custom payload file.

## Installing with pipx avoids the PEP 668 problem on Debian and Ubuntu

The installation section leads with pipx and explains why. pipx installs CLI tools into isolated environments, so oralyzer works system wide without touching the system Python, and it sidesteps the externally-managed-environment error on Debian and Ubuntu under PEP 668.

The recommended path is two commands after installing pipx itself:

```sh
# Install pipx if you don't have it
sudo apt install pipx
pipx ensurepath

# Install Oralyzer
pipx install oralyzer
```

pipx ensurepath puts the tool directory on your PATH, which is why it appears before the install step rather than after.

The alternative is a plain virtual environment, which the README presents for people who prefer pip:

```sh
python3 -m venv .venv
source .venv/bin/activate
pip install oralyzer
```

From source the same two mechanisms work, pipx install . or pip install ., and the README also shows how to skip installation entirely and run the module directly after installing the package into a virtual environment, ending with python -m oralyzer -u https://example.com/.

The package itself is small. The project metadata names it oralyzer, version 2.0.0, requires Python 3.8 or newer, and declares only two runtime dependencies, requests and beautifulsoup4. The console entry point is oralyzer.cli:main.

## Running it: one target, a file of targets, or a harvested set

The usage examples cover the three ways you normally drive a scanner of this kind:

```sh
# Single target
oralyzer -u https://example.com/login

# Multiple targets from file
oralyzer -l targets.txt

# Export findings to JSON
oralyzer -u https://example.com/login -o results.json

# CRLF injection scan
oralyzer -u https://example.com/ -crlf

# Harvest URLs from Common Crawl
oralyzer -u example.com --discover

# Use proxy
oralyzer -u https://example.com/ --proxy http://127.0.0.1:8080

# Verbose logging
oralyzer -u https://example.com/ -v

# Concurrent scanning with custom workers
oralyzer -l targets.txt --workers 10 -o results.json
```

Read the flags together and the operating model becomes clear. -u takes one URL and -l takes a file of targets, so bulk scanning is a matter of producing a file rather than learning a new flag. -o writes findings as JSON, which is what makes the output usable in a pipeline. --workers raises concurrency, and it pairs naturally with -l.

Two defaults are worth knowing before a large run. The request timeout is 10 seconds and the worker count is 5, so a scan of a slow target list will be slow before you raise anything. The --limit flag exists for the same reason, letting a run stop after a number of findings when you only need to know that a problem exists.

The proxy option is not decorative. Pointing the tool through a proxy is how you route traffic through an egress point, and it is also how you keep the source IP consistent for a session based system.

## The JSON export is built for triage, not just for archiving

The output format is a JSON array of finding objects, and the README gives a worked example:

```json
[
  {
    "type": "header",
    "request_url": "https://example.com/login?next=//evil.com",
    "payload": "//evil.com",
    "status_code": 302,
    "destination": "https://evil.com"
  },
  {
    "type": "javascript",
    "request_url": "https://example.com/page",
    "payload": "//evil.com",
    "status_code": 200,
    "sources": ["location.href", "document.URL"]
  }
]
```

Each object records the type, the exact request URL including the injected parameter, the payload that was used, the HTTP status, and then the type specific evidence: a destination host for header redirects, a list of sinks for JavaScript redirects. That combination is what makes a finding reproducible. The request_url with the payload still attached can be pasted into a browser, and the sources list points at the script context that needs fixing.

The type field also lines up with the --filter option values, so the same vocabulary is used for detection, filtering and reporting.

For a scanner whose whole purpose is producing evidence a developer can act on, that schema is the right level of detail. The project also ships its payload set as package data, since the setuptools configuration includes a data/*.txt pattern for the oralyzer package, which means a custom payload file passed with -p does not conflict with the built-in set.

## Project hygiene: setuptools packaging, pytest, mypy and ruff

The packaging metadata is modern and small. The build system requires setuptools 61.0 or newer and wheel, the package lives under src/ with setuptools.packages.find pointing there, and the console script is declared in the usual way.

The tooling configuration is worth a look because it shows what the author checks. Pytest is configured with testpaths set to tests, python_files matching test_*.py, and addopts of -v --tb=short. Mypy is configured with python_version 3.10, warn_return_any and warn_unused_configs enabled, check_untyped_defs on and disallow_untyped_defs off, which is a deliberate middle ground for a codebase that supports Python 3.8.

Ruff is the linter and formatter, with target-version py38, a line length of 100 and a lint selection of E, F, I, N and W, so pycodestyle errors, pyflakes, isort, naming and warnings. The optional dev extra installs pytest, mypy and ruff together.

The Python version support matrix runs from 3.8 through 3.12 in the classifiers, and the package status is marked as Development Status 4 - Beta. The topic list includes hacktoberfest, so contributions came in through that program rather than through a formal roadmap.

The licence is GPL-3.0, with the text in the LICENSE file at the repository root and the same identifier in the project metadata.

## What it cannot tell you, and where the release history stands

The limits are structural and worth being clear about before you trust a clean report.

Oralyzer probes URLs you give it. It is not a crawler and not a vulnerability scanner for a whole application, so a clean run means the URLs you supplied did not redirect off-site, not that the application has no open redirect. The --discover flag narrows that gap by pulling candidate URLs from a web crawl index, but a crawl index is a historical snapshot, and endpoints that were never linked from anywhere will not appear in it.

The JavaScript detection has a similar ceiling. The finding records which sinks were seen, but confirming that a DOM XSS is exploitable requires reading the application logic around the sink, and the tool's output stops at the pattern. The same goes for CRLF: the scanner sends the sequence and looks for a response change, but whether the injected content is usable depends on the framework in front of the application.

On maintenance, the repository is not archived and the last push was on 2026-09-28. The release history has one tag, v2.0.0, dated 2026-09-24, which lines up with the version field in the project metadata. A major version number on a young project with a single release tag means the interface may still change, and the README does not document a changelog policy, a payload update schedule or a compatibility promise between releases.

## Conclusion

Oralyzer fits a bug bounty hunter or security engineer who needs to check redirect parameters quickly and in bulk, and it does not fit a team that wants to certify an application or map its attack surface, because it probes URLs you already know rather than discovering endpoints for you; before running it, put the tool behind a proxy and a rate limit, and check the payload set in src/ since the package ships its payloads as data files.

## FAQ

### How do I install Oralyzer?

The recommended route is pipx, which installs the tool in an isolated environment and avoids the externally-managed-environment error on Debian and Ubuntu. Install pipx with sudo apt install pipx, run pipx ensurepath, then run pipx install oralyzer, and a plain virtual environment with pip install oralyzer works as an alternative.

### How does Oralyzer detect an open redirect?

It fuzzes the target URL with redirect payloads and reports only the ones the server actually follows to an external host. Detection covers header redirects, JavaScript redirects and meta tag redirects, and the JSON output records the request URL, the payload, the status code and the destination or the script sinks involved.

### What do the Oralyzer command line options do?

The tool takes -u for a single target, -l for a file of targets, -o to export JSON findings, -crlf to scan for CRLF injection, --discover to harvest URLs from Common Crawl, --proxy to route through a proxy, --timeout for the request timeout, --workers for concurrency, --limit to stop after N findings and --filter to restrict reporting to header, javascript, meta or crlf.

### Can Oralyzer find candidate URLs by itself?

Partly. The --discover flag harvests candidate URLs from Common Crawl's index for a domain you pass with -u, which produces a list to scan. It does not crawl the site, so endpoints that were never linked from a crawled page will not appear in the results.

## Sources

- [Issues](https://github.com/r0075h3ll/Oralyzer/issues)
- [License: GPL-3.0](https://github.com/r0075h3ll/Oralyzer/blob/master/LICENSE)
- [r0075h3ll/Oralyzer on GitHub](https://github.com/r0075h3ll/Oralyzer)
- [README](https://github.com/r0075h3ll/Oralyzer/blob/master/README.md)
- [Releases](https://github.com/r0075h3ll/Oralyzer/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/r0075h3ll-oralyzer
