Skip to content
lightosPublic

About

Panoptic is an open source penetration testing tool that automates the process of search and retrieval of content for common log and config files through path traversal vulnerabilities.

Resources

Stars

325 stars

Watchers

32 watching

Forks

Repository files navigation

Panoptic

Panoptic Logo

License: MIT Python Versions Ruff mypy GitHub last commit CodeRabbit Pull Request Reviews

Panoptic is an open source penetration testing tool that automates the search and retrieval of common log and config files through path traversal vulnerabilities.

Panoptic Demo

Features

  • Async concurrent scanning with configurable worker pool (--concurrency)
  • Automatic discovery of common log and configuration files via parameter-based, path-based, POST, cookie, header, and JSON body injection
  • FUZZ marker for arbitrary injection points — place FUZZ in any --header or --data value
  • Base64 encoding for endpoints that decode file paths (--base64)
  • Automatic OS detection with option to restrict further scans
  • Heuristic response comparison that ignores dynamic tokens (CSRF tokens, nonces, timestamps) and reflected payloads, with status code and string filtering to reduce false positives
  • Dynamic case injection — parse /etc/passwd for home directory files, mysql-bin.index for binlog files
  • Multiple output formats: text (rich), JSON, CSV (--output-format)
  • Resume/checkpoint support for long-running scans (--resume-file)
  • TOML config files for persistent settings (--config)
  • Multiple traversal bypass techniques: prefixes, postfixes, multiplier, slash replacement, double encoding
  • HTTP/HTTPS and SOCKS5 proxy support with validation
  • Random or custom User-Agent, cookie, and header support
  • Credential redaction in banner, log, and machine-readable output (including numeric and boolean JSON body values)
  • Sensitive artifacts hardened with owner-only 0600 permissions on POSIX and final-component symlink protection where the OS supports it
  • Self-update with remote URL verification (--update)

Requirements

  • Python 3.11+ (uv can download it for you, see below)
  • Git

Installation

Install Panoptic with pipx. It puts the panoptic command on your PATH and keeps Panoptic's dependencies apart from the system Python.

On Kali, Debian or Ubuntu:

sudo apt install pipx git
pipx ensurepath
pipx install git+https://github.com/lightos/Panoptic.git

On macOS, with Homebrew:

brew install pipx git
pipx ensurepath
pipx install git+https://github.com/lightos/Panoptic.git

On Windows, with Python and Git installed:

py -m pip install --user pipx
py -m pipx ensurepath
py -m pipx install git+https://github.com/lightos/Panoptic.git

Then open a new terminal and check that it works:

panoptic --version

Update with pipx upgrade panoptic. Do not run pip install panoptic: that PyPI name belongs to an unrelated project.

With uv

If your system Python is older than 3.11 (for example on Ubuntu 22.04), use uv instead. It downloads a suitable Python by itself:

curl -LsSf https://astral.sh/uv/install.sh | sh
source "$HOME/.local/bin/env"
uv tool install git+https://github.com/lightos/Panoptic.git

Then open a new terminal and run panoptic --version. Update with uv tool upgrade panoptic.

From a git checkout

To run Panoptic from a clone, for example to work on it, install it into a virtual environment inside the checkout. On Debian and Ubuntu, this needs sudo apt install python3-venv first.

git clone https://github.com/lightos/Panoptic.git
cd Panoptic
python3 -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/panoptic --version

Run it as .venv/bin/panoptic, or run source .venv/bin/activate in each new terminal to use panoptic and python panoptic.py directly. On Windows, use .venv\Scripts\python and .venv\Scripts\panoptic instead. The editable install keeps Panoptic connected to the checkout, so panoptic --update can update it in place.

Usage

panoptic --url "http://target/include.php?file=test.txt"

Examples

Basic parameter-based LFI

panoptic --url "http://target/include.php?file=test.txt"
panoptic --url "http://target/include.php?file=test.txt&id=1" \
  --param file

POST data injection

panoptic --url "http://target/include.php" \
  --data "file=test.txt&id=1" --param file

Path-based LFI

The file path replaces the last segment of the URL path. Traversal sequences such as ../ are sent exactly as written. Panoptic does not normalize them away, although the target server may.

panoptic --url "http://target/view.php/test.txt" --path-based
panoptic --url "http://target/files/view/test.txt" --path-based \
  --prefix "../" --multiplier 6

Base64-encoded parameter

panoptic --url "http://target/load.php?file=dGVzdC50eHQ=" \
  --base64 --auto

Cookie injection (FUZZ marker)

panoptic --url "http://target/page.php" \
  --header "Cookie: lang=FUZZ" --auto

JSON body injection (FUZZ marker)

panoptic --url "http://target/api/load" \
  --data '{"file":"FUZZ"}' --auto

Custom header injection (FUZZ marker)

panoptic --url "http://target/page.php" \
  --header "X-Template: FUZZ" --auto

Extension parameter

panoptic --url "http://target/view.php?file=test&type=txt" \
  --param file --ext-param type

Filter bypass with prefix

panoptic --url "http://target/filtered.php?file=test.txt" \
  --prefix "....//....//....//....//"

Encoded traversal (WAF / single-decode bypass)

Prefixes are sent exactly as given, so encoded traversal sequences reach the target unchanged. For example, in ..%252f the dots are literal and only the slash is double-encoded: the first decode turns %252f into %2f, so a filter that decodes once sees no ../, and a second decode by the application turns it into /:

panoptic --url "http://target/files/view/test.txt" --path-based \
  --prefix "..%252f" --multiplier 6

A singly encoded prefix such as %2e%2e%2f becomes ../ after one decode. It only helps against filters that inspect the raw, undecoded request:

panoptic --url "http://target/include.php?file=test.txt" \
  --prefix "%2e%2e%2f" --multiplier 6

Filtered scans

panoptic --url "http://target/include.php?file=test.txt" \
  --os "*NIX" --type conf
panoptic --url "http://target/include.php?file=test.txt" \
  --software PostgreSQL

JSON output with resume support

panoptic --url "http://target/include.php?file=test.txt" \
  --output-format json --output-file results.json \
  --resume-file scan.checkpoint

Save retrieved files

panoptic --url "http://target/include.php?file=test.txt" \
  --write-files --output-dir loot

Each found file is saved under --output-dir (default ./output), with the surrounding page template stripped where possible. File names are sanitized and kept inside the output directory.

Proxy with SSL errors ignored

panoptic --url "https://target/include.php?file=test.txt" \
  --proxy "socks5://127.0.0.1:9050" --invalid-ssl

List available filters

panoptic --list software
panoptic --list category
panoptic --list os

Comprehensive scan

panoptic --url "http://target/include.php?file=test.txt" \
  --auto --all-versions --concurrency 8

FUZZ Marker

Place FUZZ anywhere in --header or --data values to mark the injection point. Panoptic replaces FUZZ with each file path during scanning. This enables testing injection points that --param can't reach:

Injection Type Example
Cookie value --header "Cookie: theme=FUZZ"
Custom header --header "X-Include: FUZZ"
JSON body --data '{"template":"FUZZ"}'
Nested value --header "Cookie: sid=abc; lang=FUZZ"

When FUZZ is present, --param is not required.

Configuration

Panoptic supports TOML config files for persistent settings:

panoptic --url "http://target/include.php?file=test.txt" \
  --config ~/.config/panoptic/config.toml

Default config location: ~/.config/panoptic/config.toml (loaded automatically when present, even without --config).

[defaults]
# Any long option name (with dashes as underscores) is accepted here,
# including the target and output destinations.
url = "http://target/include.php?file=test.txt"
concurrency = 8
verbose = true
automatic = true
all_versions = true
output_format = "json"
output_file = "results.json"
log_file = "scan.log"
resume_file = "scan.checkpoint"

[proxy]
url = "socks5://127.0.0.1:9050"

[headers]
user_agent = "Mozilla/5.0"
cookie = "sid=foobar; auth=1"
values = ["X-Forwarded-For: 127.0.0.1"]

Priority: CLI args > config file > built-in defaults.

Config-supported target and output options

The [defaults] table accepts any scan option, not just performance tuning. In particular you can persist:

  • url — the default target (override per-run with --url)
  • output_format, output_file — where machine-readable results go
  • log_file — mirror console output to a file
  • resume_file — checkpoint location for resumable scans

Sensitive artifacts written by Panoptic — the log file, the results/list output file, and any files saved with --write-files — are forced to owner-only 0600 permissions on POSIX. Platforms exposing O_NOFOLLOW also atomically refuse a pre-existing symlink at the final path component. On platforms without O_NOFOLLOW, Panoptic performs a best-effort pre-open symlink/junction check, but the check cannot eliminate a race. Windows mode bits do not configure NTFS ACLs, so use an appropriately restricted directory when artifacts may contain sensitive data.

Overriding config booleans on the command line

Every boolean flag has a --no- counterpart, so a value set to true in the config file can be turned off for a single run without editing the file:

# config.toml sets verbose = true and automatic = true
panoptic --url "http://target/x.php?file=test.txt" --no-verbose --no-auto

Because an omitted boolean flag is left unset (rather than defaulting to false), the config value is used unless you pass the flag or its --no- form explicitly.

Proxying

Route traffic through an HTTP(S) or SOCKS proxy:

panoptic --url "https://target/x.php?file=test.txt" \
  --proxy "socks5://127.0.0.1:9050"
  • Accepted schemes: http://, https://, socks5://, socks5h:// (socks5h resolves DNS through the proxy — useful for Tor and to avoid local DNS leaks). SOCKS4 is not accepted. The scheme and host are validated before the scan starts.
  • SOCKS support comes from aiohttp-socks, which is installed by default.
  • By default Panoptic honours the standard HTTP_PROXY / HTTPS_PROXY / NO_PROXY environment variables. Pass --ignore-proxy to bypass them and connect directly. An explicit --proxy takes precedence over the environment. Credentials in ~/.netrc are never sent to the target.
  • Redirects are not followed unless you pass --follow-redirects. When a redirect leaves the original origin, your --header, --cookie and Authorization values are dropped.
  • Combine with --invalid-ssl when intercepting HTTPS through a proxy with its own CA. This disables certificate verification and is unsafe on untrusted networks.

Version Expansion (--all-versions)

Some bundled paths are version templates (for example JBoss release directories written as [JBOSS]). By default these template rows are skipped, because a literal [JBOSS] path can never match a real file. Passing --all-versions expands each template against the bundled version list, adding one concrete path per known version — a much larger but far more thorough scan:

panoptic --url "http://target/x.php?file=test.txt" --auto --all-versions

Response Comparison

Panoptic does not classify a path from the target-controlled Content-Length header alone. It compares each response body against a baseline taken from a random, nonexistent file name, and reports a file as found when the similarity falls below 0.9. Before comparing, it:

  • removes reflections of the requested path, including its prefixed, slash-replaced, Base64-, URL- and JSON-encoded forms, so error pages that echo the payload don't look like hits;
  • replaces volatile tokens (numbers, and long runs that mix letters and digits, such as CSRF tokens, nonces and session IDs) with placeholders of the same length. Dynamic pages therefore compare as identical, while token-shaped file content such as key material still counts;
  • compares only the first 64 KiB of each response. Bodies are capped at 10 MiB when downloaded, compressed bodies included.

The similarity follows Python's difflib.SequenceMatcher: lines and tags are matched first, then the characters of each region that differs. Both passes share a fixed work allowance per comparison, so a server cannot stall the scan with repetitive bodies. When the allowance runs out, which can also happen on ordinary large, repetitive pages, the regions not yet compared are scored by their longest common subsequence of characters instead. That score can be higher than the line-and-character comparison would give.

Found files are printed with their HTTP status and size, e.g. [+] Found '/etc/passwd' [200, 1.2 KB].

Resume / Checkpoints

--resume-file PATH records completed cases so an interrupted scan can continue where it left off:

panoptic --url "http://target/x.php?file=test.txt" \
  --resume-file scan.checkpoint
# ... interrupt with Ctrl-C, then re-run the same command to resume

The checkpoint stores:

  • the completed case IDs;
  • the findings so far (file path, status, size and timestamp), so the final output of a resumed scan includes them;
  • files queued from a found /etc/passwd or mysql-bin.index, and any OS restriction chosen during the scan;
  • a SHA-256 fingerprint of the scan definition: the URL, injection options, detection options, cookie, headers, --write-files and the exact case set.

It never stores credentials, headers, cookies or URLs in plaintext.

On resume, the fingerprint is recomputed and compared. If anything that would change the meaning of the scan differs, the checkpoint is rejected with a warning and the scan starts fresh. That covers a different target, parameter, filter set or --all-versions toggle, and also a different cookie or header, so a scan can't resume as another identity. A stale checkpoint therefore never silently skips cases from a different scan. The User-Agent (including --random-agent), proxy and TLS settings don't affect the fingerprint.

Checkpoints written by older Panoptic versions are rejected, and the scan starts fresh. Failed (network-error) requests are deliberately not checkpointed, so they are retried on resume.

Version and Update

panoptic --version   # print the installed version and exit
panoptic --update    # update Panoptic, or print how to update this installation

For pipx and uv installations, --update prints the command that updates them: pipx upgrade panoptic or uv tool upgrade panoptic.

From a git checkout, --update fast-forwards the checked-out main branch from the official upstream main ref. It only does so when the origin remote uses HTTPS or SSH and matches the official repository (verified before pulling, to resist insecure or tampered remote configuration). If the update changed Panoptic's dependencies, it prints the command that reinstalls them.

Other pip installations can be refreshed from the official GitHub archive:

python -m pip install --upgrade https://github.com/lightos/Panoptic/archive/refs/heads/main.zip

When run from a checkout, the banner also shows the current short git revision.

Exit Codes

Panoptic uses conventional process exit codes so it can be scripted:

  • 0 — Success: the scan (or --list / --update) completed. Individual requests that exhaust their retries are warned about and remain eligible for a resumed scan, but do not fail an otherwise successful run.
  • 1 — Invalid usage: missing or invalid arguments, or no injectable parameter could be found.
  • 2 — Operational failure: cannot connect, no matching test cases, all queued requests failed, or a worker, checkpoint, output write, or configuration failed.
  • 130 — Interrupted by the user (Ctrl-C / SIGINT).

Contributing

Contributions are welcome! Please open issues or pull requests on GitHub.

Testbed

For safe, reproducible end-to-end testing, see the Panoptic LFI Testbed. It provides deliberately vulnerable endpoints covering Panoptic's supported injection methods and traversal transformations.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Panoptic is an open source penetration testing tool that automates the process of search and retrieval of content for common log and config files through path traversal vulnerabilities.

Resources

Stars

325 stars

Watchers

32 watching

Forks

Used by

Contributors

Languages