terminus is a command-line HTTP security scanner that tests URL accessibility across methods, detects passive and active vulnerabilities, enumerates subdomains and paths, diffs scan results, and reasons over findings with built-in AI. Built in Rust with async/HTTP/3 transport.
# Install
cargo install --git https://github.com/gbiagomba/terminus.git
# Scan a single target
terminus scan -u https://example.com
# Full vuln scan with all output formats
terminus scan -f targets.txt --scan-level vuln --output-format all -o results
# AI triage of findings
terminus ai prioritize --db results.db --provider ollamaRequires Rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shOption 1 β cargo install from GitHub (recommended):
cargo install --git https://github.com/gbiagomba/terminus.gitOption 2 β clone and build:
git clone https://github.com/gbiagomba/terminus.git
cd terminus
cargo build --release
cargo install --path .HTTP/3 note: reqwest HTTP/3 requires RUSTFLAGS="--cfg reqwest_unstable". This repo sets it in .cargo/config.toml. If you build outside the repo, export it manually:
export RUSTFLAGS="--cfg reqwest_unstable"| Target | Description |
|---|---|
make build |
Compile the project |
make run |
Run with default settings |
make run-url |
Run against a specific URL, all methods |
make run-file |
Run against a file of URLs, all methods |
make install |
Install globally |
make uninstall |
Remove global install |
make clean |
Remove build artifacts |
| Subcommand | Description |
|---|---|
scan |
Primary HTTP scanning engine |
enum |
Subdomain and path enumeration |
diff |
Compare two scan outputs |
interact |
Interactive SQLite review (TUI + REPL) |
ai |
AI decision-support over SQLite evidence |
help |
Manual-style help (terminus help scan, etc.) |
Input sources:
-u <URL>β single URL or IP (IPv4/IPv6 with-6)-f <FILE>β plain text, nmap XML/greppable, testssl.sh JSON, nuclei/katana JSON- stdin pipe β
cat domains.txt | httpx | terminus
Output formats (--output-format):
stdout,txt,json,html,csv,sqlite/db,all- Use
-o <base>to set the output file name (extension added automatically)
HTML reports: vulnerability summary dashboard, JS-powered filtering by type, visual badges per finding.
SQLite: 50+ column denormalized schema, automatic indexes, schema versioning, queryable with standard SQL or via terminus interact.
- HTTP methods:
-X <METHOD>or-X ALLto test all predefined methods - Ports:
-p 80,443,8080(defaults to 80 + 443; file inputs use embedded ports automatically) - Protocol version:
--http-version 1.0|1.1|2|3 - Concurrency:
-t <N>async tasks (default: 10) - Proxy:
-x http://127.0.0.1:8080(Burp Suite, etc.) - TLS:
-kto allow insecure connections - Headers:
-H "Name: Value"(repeatable) or--header-file - Cookies:
-b "name=val"or-c/--cookie-file - Redirects:
-Lfollows HTTPLocationand JavaScript-triggered redirects (window.location,location.href,location.assign(),location.replace(), meta refresh) - Rate limiting:
--rate-limit 10/sor100/m;--random-delay 1-5for random gaps - Verbose:
-vshows full response headers
Scan level presets (--scan-level):
| Level | What it enables |
|---|---|
quick |
Basic HTTP requests only (fastest) |
standard |
Security headers + error detection + reflection |
full |
All features including body analysis and link extraction |
vuln |
All passive vulnerability detection |
- Security headers: detect missing/misconfigured CSP, HSTS, X-Frame-Options, etc. (
--check-security-headers) - Error messages: SQL errors, stack traces, path disclosure (
--detect-errors) - Reflection: passive input-reflection / XSS indicator detection (
--detect-reflection) - Body analysis:
--check-body,--extract-links,--grep-response <regex>
--crlf-desync-checkβ detect CRLF-powered request desync / HTTP request smuggling. Off by default. Also enabled via--exploit smugglingor--scan-level vuln.
Terminus uses safe, non-destructive probes issued over its own connection (no queue poisoning of shared infrastructure):
- CL.TE / TE.CL / 0.CL timing probes β measure whether ambiguous
Content-Length/Transfer-Encodingframing causes back-end read stalls Expect:header anomaly β flags unexpected417 Expectation Failedhandling- Malformed HTTP-version status probe β sends a byte-exact malformed request line and inspects the status response
- CRLF header-injection reflection: flags only when the injected marker appears as an actual response header (header block parsed), not when a framework merely echoes the encoded path in an error body
Because reqwest normalizes CRLF and cannot emit the malformed bytes these checks require, this feature ships a dedicated raw TCP+TLS transport (tokio-rustls / rustls / webpki-roots) that writes byte-exact HTTP/1.1. Findings are recorded in a CrlfDesyncResult (with desync_detected, cl_te_suspected, te_cl_suspected, zero_cl_suspected, expect_anomaly, malformed_version_anomaly, crlf_injection_reflected, baseline_ms, max_probe_ms, and issues) and surfaced across JSON, HTML, CSV, and SQLite output (new crlf_* columns).
Heuristic notes (v3.8.0): a clean rejection (
505to a malformed version,417to an unsupportedExpect) is treated as correct behavior and no longer flagged. When the target negotiates HTTP/2 or HTTP/3, the CRLF response-splitting probe is skipped (structurally impossible over binary framing) and any residual timing finding is labeled "HTTP/1.1 downgrade path only".
--malformed-verb-check: send deliberately malformed request methods over the raw socket. Off by default. Also enabled via--exploit malformedor--scan-level vuln.
Payloads (reqwest sanitizes these away, so they require the raw transport): wrong case (get, gEt), leading/trailing/embedded space, tab, control char, null byte, non-token chars (GET;, GET/, GET()), overlong token. Detects a server that accepts a malformed method (2xx/3xx), handles methods case-insensitively (method-ACL bypass risk), or hangs/resets. A clean 400/501/505 rejection is not flagged. Results land in a MalformedVerbResult (malformed_accepted, case_insensitive_methods, hang_or_reset, baseline_status, accepted_samples, issues) and the SQLite malformed_verb_* columns.
terminus scan -u https://target --malformed-verb-check -o jsonAuthorization warning: these probes can disrupt proxies and affect other users on shared infrastructure. Only run against systems you are explicitly authorized to test. Reference: PortSwigger β CRLF-powered desync attacks.
terminus scan -u https://target --crlf-desync-check -o jsonUse --exploit <module[,module]> to run active exploit modules. Combine with --payloads <file> for custom payload lists (falls back to built-in payloads when omitted).
| Module | What it tests |
|---|---|
xss |
Injects payloads into query params, checks for reflection |
sqli |
Injects payloads, looks for DB error strings |
open_redirect |
Injects redirect payloads, inspects Location header |
csrf |
Active CSRF protection checks |
ssrf |
SSRF indicator detection via URL parameters |
header |
Header injection payloads |
smuggling |
CRLF desync / HTTP request smuggling probes (see CRLF Desync detection) |
malformed |
Malformed HTTP verb probes (see Malformed HTTP verb testing) |
terminus scan -u https://target.com --exploit xss,sqli,open_redirect -k
terminus scan -u https://target.com --exploit xss --payloads payloads.txt -kterminus enum subdomains -d example.com -w words.txt
terminus enum paths -u https://example.com -w common.txt- Wildcard suppression on by default (
--no-wildcardto disable) - Filters:
-F <status>(status code), content-length - Output formats: stdout, txt, json, html, csv, sqlite, all
Compare two scans (JSON or SQLite, auto-detected):
terminus diff --base scan1.json --compare scan2.json --output-format html -o deltaDetects: new/removed endpoints, status changes, indicator deltas, header/body fingerprint changes, method-acceptance deltas.
Launch the TUI (default) or REPL against a SQLite scan database:
terminus interact --db results.db # TUI
terminus interact --db results.db --no-tui # REPLTUI keybindings:
| Key | Action |
|---|---|
β / β |
Navigate rows |
Enter |
Inspect full row details |
r |
Replay selected request |
/ |
Search (filter by URL or method) |
:open <id> |
Open scan by ID |
:replay <id> |
Replay scan by ID |
:filter status <code> |
Filter by HTTP status code |
? |
Keyboard help |
q / Esc |
Quit |
REPL commands: list urls, list methods, find status <CODE>, find exploit <TYPE>, show scan <ID>, show raw <ID>, --more (pagination), exit.
Built-in Rust AI pipeline (terminus ai) reasons over SQLite evidence using any of seven LLM providers:
| Provider | Notes |
|---|---|
openai |
Requires OPENAI_API_KEY |
openai-compatible |
Custom base URL via OPENAI_BASE_URL |
anthropic |
Requires ANTHROPIC_API_KEY |
gemini |
Requires GEMINI_API_KEY |
cohere |
Requires COHERE_API_KEY |
groq |
https://api.groq.com/openai/v1, requires GROQ_API_KEY |
ollama |
http://localhost:11434/v1, no key required |
terminus ai prioritize --db scan.db --provider openai --model gpt-4o
terminus ai prioritize --provider ollama --list-models
terminus ai prioritize --db scan.db --provider groq --model llama-3.1-8b-instant --strict-jsonOptional companion: athena.py is a standalone Python script for post-processing JSON scan output (see docs/EXAMPLES.md for usage).
Full cookbook in docs/EXAMPLES.md. Quick references:
# Scan with proxy through Burp Suite
terminus scan -u https://example.com -x http://127.0.0.1:8080 -k -v
# Passive vulnerability sweep
terminus scan -f targets.txt \
--detect-host-injection --detect-xff-bypass \
--detect-csrf --detect-ssrf --http2-desync-check \
--rate-limit 10/s -k --output-format all -o vuln_sweep
# Active exploit scan with custom payloads
terminus scan -u https://target.com --exploit xss,sqli --payloads payloads.txt -k
# CRLF desync / request smuggling detection (authorized targets only)
terminus scan -u https://target --crlf-desync-check -o json
# Subdomains + paths enumeration
terminus enum subdomains -d target.com -w subdomains.txt
terminus enum paths -u https://target.com -w common.txt
# Compare two scans
terminus diff --base scan1.json --compare scan2.json
# AI triage
terminus ai prioritize --db results.db --provider ollama
# Pipe from subfinder β httpx β terminus
subfinder -d target.com -silent | httprobe | terminus --output-format json -o resultsWhen using -X ALL, the following methods are tested:
ACL, ARBITRARY, BASELINE-CONTROL, BCOPY, BDELETE, BIND, BMOVE, BPROPFIND,
BPROPPATCH, CHECKIN, CHECKOUT, CONNECT, COPY, DEBUG, DELETE, GET, HEAD,
INDEX, LABEL, LINK, LOCK, MERGE, MKACTIVITY, MKCALENDAR, MKCOL,
MKREDIRECTREF, MKWORKSPACE, MOVE, NOTIFY, OPTIONS, ORDERPATCH, PATCH, POLL,
POST, PRI, PROPFIND, PROPPATCH, PURGE, PUT, QUERY, REBIND, REPORT,
RPC_IN_DATA, RPC_OUT_DATA, SEARCH, SUBSCRIBE, TRACE, TRACK, UNBIND,
UNCHECKOUT, UNLINK, UNLOCK, UNSUBSCRIBE, UPDATE, UPDATEREDIRECTREF,
VERSION-CONTROL, X-MS-ENUMATTS
When using --fuzz-methods, arbitrary methods are also tested (e.g., BILBAO, FOOBAR, CATS, TERMINUS, PUZZLE, HELLO). Extend with --custom-method or --custom-methods-file.
Indicators:
[Arbitrary Method Accepted]β non-standard method returned 2xx/3xx[Method Confusion Suspected]β response status differs from baseline GET
Contributions welcome β open a PR or file an issue.
GPL-3.0. See LICENSE.
.jpg)