Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Hugin

Hugin is a security intercepting proxy for web application penetration testing. It captures, inspects, and modifies HTTP/HTTPS traffic between your browser and target applications.

Key Features

  • Proxy -- HTTP/1.1, HTTP/2, and WebSocket interception with automatic per-host TLS certificates
  • Repeater -- Replay and modify requests with timing analysis and comparison
  • Intruder -- Automated fuzzing with sniper, battering ram, pitchfork, and cluster bomb attack types
  • Sequencer -- Statistical analysis of session token randomness (entropy, FIPS, bit-level)
  • Decoder -- Encode/decode chains across 20+ formats (Base64, URL, hex, HTML, JWT, and more)
  • Synaps Scanner -- WASM-based vulnerability scanner with community module marketplace
  • Active Scanner (vurl) -- Built-in checks for SSRF, SQLi, SSTI, XSS, BOLA, JWT, LDAP, and more
  • Nerve -- Passive response intelligence: parameter discovery, technology fingerprinting
  • RatRace -- Race condition testing with single-packet, last-byte sync, and barrier modes
  • Oastify -- Out-of-band detection with DNS, HTTP, SMTP, LDAP, FTP, and SMB listeners
  • Crawler -- Recursive web crawler with headless browser support
  • Lua Plugins -- Extend Hugin with Lua 5.4 scripts for custom interception logic
  • MCP Server -- Claude Desktop and Claude Code integration via 90+ MCP tools
  • Desktop GUI -- Native cross-platform desktop app (macOS, Linux, Windows)
  • REST and GraphQL API -- Full programmatic access to all features

Quick Start

# Install (macOS)
brew install HuginSecurity/tap/hugin

# Launch the desktop app
hugin

Run hugin with no arguments to open the desktop GUI. The proxy starts automatically on 127.0.0.1:8080. Configure your browser to use that address as its HTTP/HTTPS proxy, trust the Hugin CA certificate, and you're intercepting traffic.

See the Installation guide for all platforms.

Installation

Package Managers

Homebrew (macOS / Linux)

brew install HuginSecurity/tap/hugin

cargo-binstall (pre-built binary)

cargo binstall hugin-bin

AUR (Arch Linux)

yay -S hugin-proxy

Nix

nix run github:HuginSecurity/Hugin

Debian / Ubuntu

Download the .deb from the latest GitHub Release, then:

sudo dpkg -i hugin-desktop-linux-x86_64.deb

Pre-built Binaries

Download from GitHub Releases. Every release includes .sha256 checksum files and .sig Ed25519 signatures.

Available artifacts per platform:

  • macOS (Apple Silicon) -- .dmg desktop app, .tar.gz CLI binary
  • macOS (Intel) -- .dmg desktop app, .tar.gz CLI binary
  • Linux x86_64 -- .deb, .AppImage, .tar.gz
  • Linux AArch64 -- .deb, .AppImage, .tar.gz
  • Windows x86_64 -- .zip (desktop and CLI)

Verify a downloaded binary:

hugin verify hugin-desktop-darwin-aarch64.dmg

Building from Source

Requirements: Rust 1.75+ (stable), SQLite development headers.

git clone https://github.com/HuginSecurity/Hugin.git
cd hugin
cargo build --release --bin hugin

The binary is at target/release/hugin. Copy it to a directory on your $PATH.

Linux builds additionally require:

# Debian / Ubuntu
sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev

# Fedora
sudo dnf install webkit2gtk4.1-devel gtk3-devel libappindicator-gtk3-devel

# Arch
sudo pacman -S webkit2gtk-4.1 gtk3 libayatana-appindicator

Platform Notes

macOS -- Gatekeeper

Hugin ships unsigned. If macOS shows "cannot be opened because the developer cannot be verified":

  • DMG: Right-click the app, select "Open", then click "Open" in the dialog. Or:
    xattr -d com.apple.quarantine /Applications/Hugin.app
    
  • CLI tarball: After extracting:
    xattr -d com.apple.quarantine /usr/local/bin/hugin
    
  • Homebrew: No action needed. Homebrew handles quarantine automatically.

Windows -- SmartScreen

Windows may show "Windows protected your PC" for unsigned binaries. Click "More info", then "Run anyway".

Verify Installation

hugin --version

First Run

Starting Hugin

Run hugin with no arguments to launch the desktop GUI:

hugin

The proxy starts automatically on 127.0.0.1:8080 and the API server on 127.0.0.1:8081. On first run, Hugin generates a CA certificate and creates an empty project database.

CLI Mode

If you prefer to run Hugin without the GUI (headless servers, SSH sessions, CI pipelines):

# Start proxy + API in the foreground
hugin start

# Custom ports
hugin start --port 9090 --api-port 9091

# Start with MCP server for Claude integration
hugin start --mcp

# Verbose logging
hugin start -v

Press Ctrl+C to stop the proxy.

Headless Server Mode

For remote/team access, use serve which binds to 0.0.0.0 by default:

hugin serve

This requires token authentication. Create tokens with hugin token create.

Setup Wizard

On first launch, Hugin runs a setup wizard that walks through proxy port selection, CA certificate installation, and optional Pro license activation. You can re-run it any time:

hugin setup

For non-interactive environments:

hugin setup --headless

Data Directory

All Hugin data lives under ~/.config/hugin/:

~/.config/hugin/
  config.toml              Configuration file
  Hugin-Proxy-CA.pem       CA certificate (install in your browser/OS)
  Hugin-Proxy-CA-key.pem   CA private key (keep private)
  hugin.db                 SQLite database (flows, findings, projects)
  modules/                 Synaps scanner modules (WASM)
  extensions/              Lua plugin scripts

Generate a Default Config

If you want to customize settings before starting:

hugin init

This writes a default config.toml to ~/.config/hugin/config.toml. See Configuration for details.

Export the CA Certificate

To export the CA certificate to a specific location:

hugin ca --output ~/Desktop/hugin-ca.pem

Or print it to stdout:

hugin ca --print

The certificate is also downloadable from the API at http://127.0.0.1:8081/api/ca.pem while Hugin is running.

Browser Setup

Hugin intercepts HTTP/HTTPS traffic by acting as a proxy. You need to (1) point your browser at the proxy and (2) trust the Hugin CA certificate.

Quick Setup (Mullvad Browser)

Click the Mullvad Browser button in the Hugin toolbar. Hugin automatically:

  1. Creates a temporary Firefox profile with the proxy pre-configured
  2. Imports the Hugin CA certificate
  3. Disables certificate pinning, HSTS preload, and HTTPS-Only Mode
  4. Disables the Mullvad Browser Extension (which would override proxy settings)
  5. Launches the browser in an isolated profile

No manual configuration needed. Your normal Mullvad Browser profile is untouched.

Requirement: certutil must be installed (brew install nss on macOS).

Manual Setup

Step 1: Configure the Proxy

Set your browser to use 127.0.0.1 port 8080 as its HTTP and HTTPS proxy.

Firefox / Mullvad Browser

Settings > Network Settings > Manual Proxy Configuration:

  • HTTP Proxy: 127.0.0.1, Port: 8080
  • Check "Also use this proxy for HTTPS"

Mullvad Browser -- Extra Settings

Mullvad Browser requires additional about:config overrides:

  • security.enterprise_roots.enabled = true
  • security.cert_pinning.enforcement_level = 0
  • network.stricttransportsecurity.preloadlist = false
  • dom.security.https_only_mode = false
  • dom.security.https_only_mode_ever_enabled = false
  • dom.security.https_only_mode_pbm = false
  • extensions.torlauncher.start_tor = false
  • extensions.installDistroAddons = false

The Mullvad Browser Extension uses browser.proxy.onRequest to route all traffic through a SOCKS proxy, overriding your manual settings. Disable it via Add-ons > Extensions, or set extensions.installDistroAddons to false.

Mullvad Browser resets prefs.js on each startup. Use user.js in the profile directory for persistent settings.

Chrome / Chromium

Chrome uses system proxy settings. Alternatively, launch with a flag:

chromium --proxy-server="http://127.0.0.1:8080"

macOS System Proxy

System Settings > Network > (your adapter) > Advanced > Proxies:

  • HTTP Proxy: 127.0.0.1:8080
  • HTTPS Proxy: 127.0.0.1:8080

Step 2: Trust the CA Certificate

Hugin generates a CA certificate at ~/.config/hugin/Hugin-Proxy-CA.pem on first run. Your browser or OS must trust this certificate for HTTPS interception.

You can also download it from http://127.0.0.1:8081/api/ca.pem while Hugin is running.

macOS (System Keychain)

sudo security add-trusted-cert -d -r trustRoot \
  -k /Library/Keychains/System.keychain \
  ~/.config/hugin/Hugin-Proxy-CA.pem

Linux (System-wide)

sudo cp ~/.config/hugin/Hugin-Proxy-CA.pem /usr/local/share/ca-certificates/hugin-ca.crt
sudo update-ca-certificates

Windows (Administrator)

certutil -addstore Root %USERPROFILE%\.config\hugin\Hugin-Proxy-CA.pem

Firefox (Manual Import)

Firefox uses its own certificate store, separate from the OS:

  1. Settings > Privacy & Security > Certificates > View Certificates
  2. Authorities tab > Import
  3. Select ~/.config/hugin/Hugin-Proxy-CA.pem
  4. Check "Trust this CA to identify websites"

Or via command line with certutil (from NSS tools):

certutil -A -n "Hugin Proxy CA" -t "CT,C,C" \
  -i ~/.config/hugin/Hugin-Proxy-CA.pem \
  -d "sql:$(find ~/Library/Application\ Support/Firefox/Profiles -name '*.default-release' | head -1)"

Chrome on Linux

certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "Hugin CA" \
  -i ~/.config/hugin/Hugin-Proxy-CA.pem

Verifying the Setup

  1. Start Hugin
  2. Open the configured browser
  3. Visit any HTTPS site (e.g., https://httpbin.org/get)
  4. Check the HTTP History tab in Hugin -- you should see the request appear
  5. No certificate warnings should appear in the browser

If you see certificate errors:

  • Verify the CA cert is imported and trusted
  • For Mullvad Browser: confirm security.cert_pinning.enforcement_level = 0
  • For HSTS-protected sites: confirm network.stricttransportsecurity.preloadlist = false

Scope

By default, Hugin captures all traffic through the proxy. To limit capture to specific targets, configure scope in the Scopes view within the UI, or edit config.toml:

[scope]
include_hosts = ["*.example.com", "api.target.com"]
exclude_hosts = ["fonts.googleapis.com", "*.analytics.com"]

Mullvad VPN Compatibility

Hugin works alongside Mullvad VPN. Browser traffic routes through the Hugin proxy on localhost, then Hugin's outbound connections go through the VPN tunnel. Enable split tunneling in the Mullvad app if you experience connectivity issues.

Configuration

Hugin stores its configuration at ~/.config/hugin/config.toml. Generate a default config with:

hugin init

View the current configuration:

hugin config show

Proxy

[proxy]
listen_addr = "127.0.0.1:8080"     # Proxy listen address
api_addr = "127.0.0.1:8081"        # API / MCP server address
upstream_proxy = "socks5://127.0.0.1:9050"  # Route traffic through Tor, Burp, etc.
invisible_proxy = false             # Transparent proxy mode (no browser config needed)
additional_ports = [8443]           # Extra ports to listen on

CA Certificate

[ca]
cert_path = "~/.config/hugin/Hugin-Proxy-CA.pem"
key_path = "~/.config/hugin/Hugin-Proxy-CA-key.pem"
cache_size = 1000                   # Per-host certificate cache size

Storage

[storage]
db_path = "~/.config/hugin/hugin.db"
max_body_size = 10485760            # Max response body stored per flow (10 MB)

Scope

[scope]
include_hosts = ["*.example.com"]   # Only capture matching hosts (empty = all)
exclude_hosts = ["*.analytics.com"] # Never capture matching hosts

Scope can also be configured in the Scopes view within the desktop UI.

HTTP/2

[http2]
enabled = true
alpn_protocols = ["h2", "http/1.1"]
enable_server_push = true
max_concurrent_streams = 100

Force HTTP/1.1 for specific hosts:

[[http2.host_overrides]]
pattern = "legacy.example.com"
http_version = "ForceHttp11"

Oastify (Out-of-Band Detection)

[oastify]
enabled = false
base_url = "https://oastify.eu"
domain = "oastify.eu"
api_token = "your-token"
poll_interval_ms = 5000
session_ttl_hours = 24

API Authentication

[api]
auth_enabled = false
auth_username = "admin"
auth_password = "changeme"
auth_token = "bearer-token-here"

Enable authentication when exposing the API beyond localhost (e.g., with hugin serve).

Telemetry

[telemetry]
enabled = false                     # Opt-in anonymous usage telemetry

Toggle from the CLI:

hugin config telemetry on
hugin config telemetry off

External Tools

[tools]
xmass_api = "http://127.0.0.1:8080"
vectorsploit_hub = "http://127.0.0.1:50051"
subflow_path = "/usr/local/bin/subflow"

Proxy

Hugin's proxy is a full MITM (man-in-the-middle) HTTP and WebSocket proxy. It sits between your browser and the target application, decrypting TLS traffic, capturing every request and response, and feeding them to all other tools in real time.

Getting Started

  1. Start Hugin. The proxy listens on 127.0.0.1:8080 by default.
  2. Install the CA certificate (see below).
  3. Configure your browser to use 127.0.0.1:8080 as its HTTP/HTTPS proxy.
  4. Browse the target application. All traffic appears in the History view.

How It Works

For plain HTTP, the proxy captures requests and responses directly.

For HTTPS, the flow is:

  1. Your browser sends a CONNECT tunnel request for the target host.
  2. Hugin completes the TLS handshake with the browser using a dynamically generated certificate for that host.
  3. Hugin establishes a separate TLS connection to the upstream server.
  4. Every request and response is captured as an HTTP flow and stored in the database.
  5. The flow is broadcast to the UI, scanner, and any loaded plugins immediately.

HTTP/2 Support

HTTP/2 is enabled by default. The proxy negotiates the protocol via ALPN during the upstream TLS handshake. When the server speaks HTTP/2, Hugin uses a persistent connection pool keyed by host. Pseudo-headers (:method, :path, :authority, :scheme) are captured alongside regular headers so HTTP/2 flows are fully inspectable.

HTTP/2 can be disabled in configuration if a target misbehaves with it.

CA Certificate

On first launch, Hugin generates an RSA CA key pair and writes it to disk. You install the CA certificate once so your browser trusts the proxy's per-host certificates.

Installation:

  • macOS -- double-click the certificate, add to Keychain, mark as "Always Trust"
  • Firefox -- Settings > Privacy & Security > Certificates > View Certificates > Import
  • Chrome/Chromium -- follows the OS trust store on macOS and Linux

The CA cert PEM is served at http://localhost:8080/ca.pem for easy download. You can also export it via the CLI:

hugin ca --print
hugin ca --output ~/ca.crt

Scope Filtering

Scope controls what gets captured and stored. Four modes are available:

  • CaptureAll (default) -- every flow is stored regardless of host
  • InScopeOnly -- only flows matching at least one include pattern are stored
  • OutOfScopeOnly -- flows matching exclude patterns are dropped before storage
  • CaptureAllTagOOS -- all flows are stored, but out-of-scope flows are tagged

Scope patterns can match on host, URL prefix, or regular expression. Scope is updated at runtime without restarting the proxy; changes take effect on the next request.

Out-of-scope traffic is always forwarded transparently -- the browser still gets its responses, they just are not stored.

Upstream Proxy Chaining

Hugin can route traffic through an upstream proxy. Supported types:

  • HTTP and HTTPS proxies
  • SOCKS4 and SOCKS5 proxies
  • Per-host routing rules with wildcard patterns and priority ordering
  • Basic authentication for proxies that require credentials
  • A built-in tor preset routing through socks5://127.0.0.1:9050

Per-host rules are evaluated in priority order (higher numbers first). If no rule matches, Hugin falls back to the global proxy or connects directly.

WebSocket Detection

When the proxy sees an Upgrade: websocket request, it hands the connection to the WebSocket manager. The HTTP 101 handshake is recorded as a normal flow, and all subsequent frames are captured separately. See WebSocket for details.

Plugin and Extension Hooks

Every proxied flow passes through the plugin bus before being stored. Registered plugins can modify, flag, or drop requests and responses. Lua extensions can hook OnRequest and OnResponse to modify traffic in-flight.

Flow Recording

Flow recording can be paused and resumed without stopping the proxy. When paused, the proxy still forwards traffic but does not write flows to the database. This is useful when you want to reduce noise while performing a specific test.

Configuration

Proxy settings are stored in hugin.toml:

[proxy]
listen_addr = "127.0.0.1:8080"

[ca]
cert_path = "~/.hugin/ca.crt"
key_path  = "~/.hugin/ca.key"

[http2]
enabled        = true
alpn_protocols = ["h2", "http/1.1"]

CLI

hugin start                        # Start proxy on default port
hugin start --port 9090            # Start on custom port
hugin start --bind 0.0.0.0         # Bind to all interfaces
hugin status                       # Show proxy status
hugin ca --print                   # Print CA certificate to stdout

MCP Tool

proxy_status -- proxy infrastructure info.

Actions: health, status, ca_cert

scope -- manage proxy scope.

Actions: get, set_mode, add_pattern, remove_pattern, update, export, import, save_preset, load_preset, list_presets, delete_preset, from_sitemap

Intercept

The Intercept view lets you observe, inspect, and modify HTTP traffic in real time as it flows through the proxy. It operates in three states controlled by two toolbar toggles.

Operating Modes

Intercept OFF (default)

Full passthrough. Nothing is captured or displayed in the intercept view. Traffic flows through the proxy silently and is recorded to history as normal.

Header pill: Intercept off (green).

Observe Mode (Intercept ON, Hold OFF)

Traffic flows through the proxy without interruption -- the browser never stalls. Requests appear in the intercept view as a live feed (last 500, ring buffer). You can scroll through them and inspect details, but you cannot modify or block them since they have already been sent.

Use this when you want to watch traffic without interfering: mapping the application, understanding flows, looking for interesting endpoints.

The Clear button wipes the captured list.

Header pill: Intercept (green).

Hold Mode (Intercept ON, Hold ON)

Blocking mode. Every request that matches the intercept scope (and is not auto-handled by an Intercept Rule) is held in a queue. The browser stalls until you release the request.

Four action buttons appear:

  • Forward -- release the selected request as-is (or after editing in the detail pane)
  • Forward All -- release all queued requests at once
  • Drop -- discard the selected request; the browser gets an error
  • Drop All -- discard all queued requests

Click a request in the list to select it, inspect its full HTTP content in the detail pane below, edit headers or body, then click Forward to send the modified version.

Header pill: Hold (red).

Keyboard shortcuts: Ctrl+; forwards the selected request, Ctrl+D drops it.

Scope

Intercept only captures requests to hosts matching the configured scope patterns. Empty scope means capture everything. Scope is configured in the Scopes view and shared with the proxy.

Capture Options

Two checkboxes in the toolbar control what gets captured beyond standard requests:

  • Responses -- also intercept HTTP responses (hold mode only)
  • WebSockets -- also intercept WebSocket messages

When response interception is enabled, responses are held separately and can be individually forwarded, modified, or dropped.

Intercept Rules

The gear icon opens the Intercept Rules panel. Rules run before the observe/hold decision and can automatically forward, drop, modify, or flag requests without manual intervention. See Intercept Rules for the full reference.

MCP Tool

intercept -- MITM intercept control.

Actions:

  • status -- current state (enabled, hold, pending counts, recording status)
  • toggle -- set enabled/hold/intercept_responses/recording
  • recording -- toggle flow recording on or off
  • list -- list pending requests (hold mode)
  • get -- get a specific pending request
  • forward -- forward a held request
  • drop -- drop a held request
  • forward_all -- forward all held requests
  • drop_all -- drop all held requests
  • responses -- list pending responses
  • response_get -- get a specific pending response
  • response_forward -- forward a held response
  • response_drop -- drop a held response
  • responses_forward_all -- forward all held responses
  • responses_drop_all -- drop all held responses

API

Direct REST access for scripting:

GET  /api/intercept/status
POST /api/intercept/toggle              {"enabled": true, "hold": false}
GET  /api/intercept/pending
GET  /api/intercept/captured
POST /api/intercept/captured/clear
POST /api/intercept/{id}/forward
POST /api/intercept/{id}/drop
POST /api/intercept/forward-all
POST /api/intercept/drop-all

Repeater

Repeater lets you replay captured HTTP flows with arbitrary modifications. Change headers, body, method, URL, or redirect the request to a different server -- all without touching your browser.

Workflow

  1. Right-click any flow in the History view and choose "Send to Repeater", or use the MCP tool to send it programmatically.
  2. The flow appears in the Repeater tab.
  3. Edit headers, body, URL, or method in the editor panel.
  4. Click Send. The response appears immediately alongside the original.
  5. The exchange is recorded in repeater history and linked back to the original flow.

Request Modifications

Every send operation accepts modifications:

  • headers_add -- list of [name, value] pairs appended to the request
  • headers_remove -- list of header names to strip (case-insensitive)
  • body -- replaces the request body (UTF-8 string, raw bytes, or null to remove)
  • url -- replaces the URL; can be absolute (https://other.host/path) or relative (/api/v2/users)
  • method -- replaces the HTTP verb
  • target_override -- redirects the TCP connection to a different host:port while keeping the original URL in the request line

When a URL is relative (no ://), Hugin merges it with the scheme and authority of the original URL. This lets you test path variations without retyping the full URL.

Browser-Routed Requests

Set browser_port to route the request through a running browser's fetch() API. This gives the request a real browser TLS fingerprint (JA3/JA4), bypassing WAF bot detection systems like Akamai BMP, DataDome, and Cloudflare Bot Management.

Batch Send Modes

Send multiple requests in one operation with three concurrency modes:

  • sequential (default) -- send one at a time, wait for each response
  • sync -- fire all requests simultaneously from a synchronized barrier; useful for race condition testing
  • parallel -- concurrent with a configurable worker limit

Batch results include per-request status codes, latency, response size, and the new flow ID for each replay. Aggregate timing statistics (min, max, mean, stddev) are included when sending more than one request.

Raw Send

The raw_send action sends a single raw HTTP request via a direct socket connection with full TLS and SOCKS5 proxy support. Use batch_raw_send for parallel raw requests. The repeat action sends raw requests through the proxy so the flow is captured in history.

Queue Management

The queue is persistent and backed by SQLite. If you close Hugin and reopen it, pending requests survive.

  • list -- view all pending items with status (pending, in_progress, completed, failed)
  • cancel -- remove a specific item before it is sent
  • clear -- remove all pending items

History is capped at 1,000 entries. Older entries are pruned automatically.

History

Every completed send is recorded. History entries include:

  • Original flow ID and new flow ID (the replayed pair)
  • Method, URL, HTTP status code
  • Latency in milliseconds
  • Timestamp

MCP Tool

repeater -- HTTP request repeater.

Actions: send, history, queue, queue_status, raw_send, batch_raw_send, repeat, repeat_flow, batch_send, list_queue, cancel, clear_queue, proxy_status, compare

API

POST /api/repeater/queue              {"flow_id": "uuid", "modifications": {...}}
POST /api/repeater/send               {"id": "uuid-of-queued-item"}
POST /api/repeater/batch              {"items": [...], "mode": "sync"}
GET  /api/repeater/history?limit=50

Intruder

Intruder is Hugin's automated attack engine. Mark positions in a request with injection markers (§name§), choose payload generators and processors, and Intruder fires every payload through those positions while recording response status codes, lengths, timing, and pattern matches.

Quick Start

  1. Capture a request in the proxy.
  2. Send it to Intruder.
  3. Mark injection points by wrapping values with § markers: /api/users/§id§.
  4. Configure payload generators for each position.
  5. Start the attack.
  6. Review results, filtering by status code, response length, or timing anomalies.

Payload Generators (19 types)

Each generator produces a lazy iterator of strings. Generators do not materialize the full list in memory unless required.

SimpleList -- a fixed list of strings you provide inline. The most common generator for custom wordlists.

Numbers -- a numeric range with step. Supports zero-padded formatting ({:04}) and negative steps for descending ranges. Example: start=1, end=100, step=1 produces 1 through 100.

BruteForcer -- all permutations of a character set between a minimum and maximum length. Built-in charsets: lowercase, uppercase, digits, alphanumeric, hex. Maximum string length is capped at 12; maximum total payloads is 1,000,000.

Dates -- a date range with a strftime format string. Useful for brute-forcing date-based tokens or IDs. Example: start=2024-01-01, end=2024-12-31, format=%Y%m%d.

CharacterSubstitution -- generates all combinations of a base string where specific characters are replaced by alternatives. Includes a built-in leet-speak rule set (a->4/@, e->3, etc.) or define your own substitution map.

CharFrobber -- applies character manipulations to a base string: toggle case per-character, toggle entire string, increment/decrement character codes, reverse, shift by offset. Produces the original plus all derived variants.

BitFlipper -- flips bits in a base value systematically. Five modes: SingleBit (one bit at a time), SingleByte (XOR each byte with 0xFF), BitPairs (flip consecutive bit pairs), BytePairs (flip consecutive byte pairs), Nibble (flip each 4-bit nibble).

NullPayloads -- emits N copies of an empty string, or a fixed set of 14 null-like values (null, NULL, nil, None, undefined, NaN, 0, -1, false, \0, \x00, %00, {{null}}, and empty string).

UsernameGenerator -- generates username variations from first/last name pairs. Patterns: first.last, first_last, flast, firstl, first, last, first.last1..99. Includes a CommonNames pattern that emits 25 common admin/system usernames.

RuntimeFile -- reads payloads line by line from a file at attack time. Blank lines and comment lines (starting with #) are skipped. Validates the file path against an optional base directory to prevent path traversal.

ExtensionGenerated -- a custom generator backed by a Lua extension closure. Lets extensions inject dynamic payload sequences at runtime.

CharacterBlocks -- generates strings of a single character repeated at varying lengths. Useful for buffer overflow testing and length-based fuzzing. Configurable character, min/max length, and step.

CustomIterator -- generates combinations from multiple word lists joined by a separator. Useful for producing structured strings like admin-dev-01, admin-staging-02.

IllegalUnicode -- generates illegal and malformed Unicode sequences for testing parser robustness. Categories include overlong UTF-8, surrogate pairs, BOM variations, and null bytes. Output is percent-encoded for safe transport.

CaseVariant -- generates case variations of base words: uppercase, lowercase, proper case, inverted case. Deduplicates results since different modes may produce identical output for certain inputs.

OastifyPayloads -- generates out-of-band (OOB) callback payloads using the built-in Oastify system. Each payload contains a unique correlation ID for tracking interactions. Supports DNS, HTTP, HTTPS, SMTP, LDAP, FTP, and SMB protocols.

EcbBlockShuffler -- rearranges ciphertext blocks to test ECB-mode encryption vulnerabilities. Operations include removing blocks, duplicating blocks, swapping pairs, reversing order, and generating all permutations. Supports hex and base64 encoded ciphertext with 8-byte (DES) or 16-byte (AES) block sizes.

CopyOtherPayload -- copies the payload from another position. Resolved during generation; used when two positions must receive the same value.

PayloadSet Combination Modes

When an attack uses multiple payload positions, generators are combined:

  • concat -- all payloads from generator 1, then all from generator 2 (serial)
  • zip -- pairs payloads position by position; stops when the shortest generator is exhausted
  • product -- Cartesian product of all generators (every combination). Capped at 10,000,000 total combinations.

Payload Processors (15 types)

Processors transform each payload before injection. Chain multiple processors to build complex transformations.

  • AddPrefix / AddSuffix -- prepend or append a fixed string
  • MatchReplace -- regex or literal find/replace within the payload
  • UrlEncode / UrlDecode -- percent encoding; configurable to encode all characters or only special ones
  • HtmlEncode / HtmlDecode -- HTML entity encoding
  • Base64Encode / Base64Decode -- standard Base64
  • Hash -- hash the payload with MD5, SHA-1, SHA-256, or SHA-512
  • CaseModification -- uppercase, lowercase, or toggle case
  • Substring -- extract a substring by start and optional end index
  • ReverseString -- reverse the payload
  • SkipIfMatch -- drop the payload entirely if it matches a pattern (filter)
  • InvokeExtension -- pass the payload to a Lua extension function for arbitrary transformation

Response Analysis: Grep Match

Attach grep matchers to flag responses containing (or missing) specific content:

  • Contains -- substring match, optionally case-sensitive
  • NotContains -- inverse match
  • Regex -- regular expression match with a 1 MB size limit to prevent ReDoS

Match results include the patterns that fired and byte offsets within the response body.

Response Analysis: Grep Extract

Extractors pull values out of responses:

  • from_regex(name, pattern, group) -- captures a named group from each response
  • from_delimiters(name, start, end) -- extracts content between two delimiter strings

Extracted values are stored per-result and visible in the results table.

Result Filtering and Sorting

Results can be filtered by:

  • Exact status code or status code range (e.g., 2xx)
  • Response length (min, max)
  • Response time (min, max)
  • Whether a grep match fired
  • Whether a specific key was extracted
  • Errors only or exclude errors

Results are sortable by payload, request ID, status code, response length, or response time.

Grep Local

The grep_local action provides fast Rust-native regex searching across attack results. Supports filters for status codes, response time ranges, length ranges, field selection (body, headers, status), and result inversion.

Resource Pool

Each attack runs with a configurable concurrency limit controlling how many requests are in-flight simultaneously. Rate limiting is enforced between requests. Attacks can be paused and resumed.

CSV Export

Any result set can be exported to CSV. The export includes request ID, payload, status code, response length, response time, grep match flag, matched patterns, extracted values, and error message.

MCP Tool

intruder -- attack automation engine.

Actions: start, run (standalone, no proxy required), list, get, status, pause, resume, cancel, delete, results, grep_local, grep_data, processing, export

The run action executes an attack inline and returns results directly -- useful for quick one-off fuzzing from MCP without managing attack state.

API

POST /api/intruder/attacks              Start a new attack
GET  /api/intruder/attacks              List all attacks
GET  /api/intruder/attacks/{id}         Get attack details
GET  /api/intruder/attacks/{id}/results Get results
POST /api/intruder/attacks/{id}/pause   Pause
POST /api/intruder/attacks/{id}/resume  Resume
POST /api/intruder/attacks/{id}/cancel  Cancel

Sequencer

Sequencer analyzes the statistical quality of tokens -- session IDs, CSRF tokens, password-reset links, API keys, or any value an application generates. It tells you whether the tokens are cryptographically random or follow a pattern that an attacker could predict.

Quick Start

  1. Identify a token you want to analyze (session cookie, CSRF token, etc.).
  2. Start a capture session targeting that token, or paste a list of collected tokens.
  3. Collect at least 100 tokens (2,500+ bytes for FIPS tests).
  4. Run the analysis.
  5. Review the quality grade and individual test results.

Analysis Pipeline

Shannon Entropy

Entropy is calculated in bits per byte over the byte distribution of all tokens concatenated. A perfect random byte sequence scores 8.0 bits. Printable ASCII strings are bounded by the character set -- a hex-only token tops out around 4.0 bits (16 symbols). Entropy below 4.0 bits is a strong signal of poor randomness.

Bit-Level Analysis

Each of the 8 bit positions (0-7) is analyzed independently. For each position, Sequencer calculates the probability it is set to 1 across all token bytes. An ideal random generator produces 0.5 for every position. Any position more than 5% away from 0.5 is flagged as biased. Common findings: ASCII bit 7 is always 0 for printable strings; base64 tokens constrain multiple bit positions.

FIPS 140-2 Tests

All four FIPS 140-2 statistical randomness tests are implemented. These require at least 2,500 bytes (20,000 bits) of token data -- collect enough samples before interpreting FIPS results.

Monobit Test -- counts the number of 1 bits in a 20,000-bit sample. Must fall between 9,725 and 10,275.

Poker Test -- divides bits into 5,000 four-bit segments and applies a chi-square test over the 16 possible patterns. Statistic X must be between 2.16 and 46.17.

Runs Test -- counts consecutive runs of 0s and 1s in six length categories (1 through 6+). Each category must fall within bounds derived from the FIPS standard.

Long Runs Test -- no run of consecutive identical bits may exceed 25 bits. Tokens with long static prefixes commonly fail here.

All four tests must pass for overall_pass to be true.

Pattern Detection

Sequencer scans the token list for structural patterns:

  • Common prefix -- all tokens share a leading substring of 2+ characters. Prefixes longer than 4 characters are rated High severity.
  • Common suffix -- same analysis for trailing substrings.
  • Sequential -- tokens parse as integers forming an arithmetic sequence. Rated Critical.
  • Repeating -- tokens that appear more than once. More than half being duplicates is Critical.
  • Charset restriction -- all tokens use only one character class (lowercase, uppercase, digits, hex). Hex-only is informational; other single-class restriction is Medium.

Correlation Analysis

When 100+ bytes of data are available, Sequencer calculates the serial correlation coefficient and auto-correlation at up to 20 lags. A coefficient above 0.1 indicates statistically significant correlation. Correlation above 0.3 reduces the quality score significantly.

Quality Grades

The analysis produces a single quality grade backed by a numeric score (0-100):

  • Excellent (>= 85) -- suitable for cryptographic use
  • Good (>= 65) -- passes all standard tests
  • Fair (>= 45) -- minor concerns
  • Poor (>= 25) -- not suitable for security purposes
  • Critical (< 25) -- highly predictable

Scoring deductions: low entropy (-10 to -40), failed FIPS tests (-30 for overall fail, up to -15 for individual), significant correlation (-20), detected patterns (-8 to -25 depending on severity), biased bit positions (-10 to -20).

Capture Modes

Tokens can reach Sequencer in two ways:

  • Live capture -- start a capture session that sends repeated requests and extracts the target token from each response automatically.
  • Manual paste -- paste a list of tokens directly or submit them via the API.

Comparing Token Sets

The compare action lets you compare two sets of tokens side by side -- useful for checking whether a fix improved randomness quality or whether tokens from different endpoints share weaknesses.

Output

The analysis report includes:

  • Quality grade and numeric score
  • Entropy value in bits
  • Bit-position analysis showing bias per position
  • FIPS test results with pass/fail, computed value, and expected threshold range
  • Correlation coefficient and auto-correlation values
  • Detected pattern list with severity, type, and confidence
  • Entropy distribution chart (ASCII visualization per 64-byte block)

MCP Tool

sequencer -- token randomness analysis.

Actions:

  • capture -- start collecting tokens from repeated requests
  • tokens -- poll collected tokens from an active session
  • stop -- stop capture
  • analyze -- run statistical analysis on collected tokens
  • list -- list active sessions
  • delete -- remove a session
  • status -- get session status with all tokens
  • compare -- compare two token sets
  • export -- export session with full analysis report

Decoder

Decoder is a multi-format encode/decode/hash/transform workbench with a built-in polyglot payload library. Paste a value, pick an operation, get the result. All operations are stateless -- nothing is stored or logged.

Encode Operations

  • base64 -- standard Base64 with = padding
  • url -- percent encoding
  • html -- HTML entity encoding (< to &lt;, etc.)
  • unicode -- Unicode escape sequences (A to \u0041)
  • hex -- lowercase hex encoding of UTF-8 bytes
  • base32 -- RFC 4648 Base32 with = padding
  • ascii85 -- Adobe/PostScript Ascii85 encoding
  • rot13 -- Caesar cipher with 13-character rotation (symmetric: encode = decode)
  • binary -- space-separated 8-bit binary representation per byte
  • octal -- space-separated 3-digit octal representation per byte
  • gzip -- gzip-compress the input, return Base64 of the compressed bytes
  • deflate -- DEFLATE-compress the input, return Base64 of the compressed bytes
  • jwt_none -- encode a JWT with alg: none and no signature

Decode Operations

All encode operations have a corresponding decode operation. Additional notes:

  • gzip and deflate expect Base64-encoded compressed data on input
  • binary expects space-separated 8-bit groups
  • octal expects space-separated 3-digit groups
  • unicode replaces \uXXXX sequences with their code points
  • hex strips spaces before parsing
  • jwt decodes a JWT token (see JWT Decode below)

Hash Algorithms

Hashing is one-way and returns a lowercase hex digest.

  • md5 -- MD5 (128-bit)
  • sha1 -- SHA-1 (160-bit)
  • sha256 -- SHA-256
  • sha512 -- SHA-512
  • sha3_256 -- SHA-3 256-bit
  • sha3_512 -- SHA-3 512-bit
  • blake2b -- BLAKE2b
  • blake2s -- BLAKE2s
  • ripemd160 -- RIPEMD-160
  • crc32 -- CRC-32 (non-cryptographic; useful for checksum verification)

Transform Operations

Transforms manipulate text without encoding or decoding:

  • lowercase / uppercase -- case conversion
  • reverse -- reverse character order
  • length -- return the byte count
  • trim -- remove leading and trailing whitespace
  • remove_whitespace -- remove all whitespace characters
  • remove_newlines -- remove \n and \r characters

JWT Decode

Splits a JWT at the . delimiters, Base64url-decodes the header and payload, and returns them as parsed JSON alongside the raw signature.

JWT Forge

Constructs a new JWT from arbitrary header and payload JSON objects.

  • none -- no signature; produces header.payload. with empty signature
  • hs256 -- HMAC-SHA256 with a provided secret key

The forged token is ready to paste into Repeater or an Intruder payload list.

Chained Operations

The chain action applies a sequence of operations in order, passing the output of each step as the input to the next.

Operations are specified as strings with an optional prefix:

  • encode:base64 -- explicitly encode
  • decode:url -- explicitly decode
  • base64 -- defaults to encode when no prefix is given

Each step is recorded in the response so you can see the intermediate value at every stage.

Example chain: ["decode:base64", "decode:url", "encode:html"]

Auto-Analysis

The analyze action inspects an unknown value and returns a confidence-ranked list of detected encodings:

  • Base64 (0.9 confidence) -- length divisible by 4, valid character set
  • URL encoding (0.95) -- presence of %XX sequences
  • HTML entities (0.9) -- presence of &amp;, &lt;, or &#
  • Hex (0.7) -- all hex-valid characters, even length
  • Unicode escapes (0.95) -- presence of \uXXXX patterns
  • JWT (0.95) -- three dot-separated Base64url segments
  • Base32 (0.6) -- characters in [A-Z2-7=]

Also returns input length and Shannon entropy to help distinguish encoded data from random noise.

Re-encode Conversion

The reencode action takes a value and attempts all pairwise conversions between base64, url, html, hex, and unicode. Returns every successful from -> to conversion path with intermediate decoded values.

Polyglot Payloads

The polyglot action generates WAF bypass payloads from a library of 622 payloads across 66 vulnerability contexts:

XSS, SQLi, NoSQL injection, command injection, SSTI, XXE, SSRF, path traversal, LFI, RFI, LDAP injection, CRLF injection, open redirect, prototype pollution, deserialization, GraphQL injection, Log4j/Log4Shell, CSV injection, HTTP request smuggling, host header injection, CORS bypass, JWT attacks, file upload bypass, LLM/prompt injection, XPath injection, OAuth abuse, race conditions, email header injection, API abuse, and error disclosure.

Optional filters:

  • context -- filter by vulnerability type (e.g., xss, sqli)
  • waf -- apply WAF-specific evasion transformations (cloudflare, akamai, aws, modsecurity, imperva, f5, barracuda)
  • limit -- maximum number of payloads to return (default 100)

MCP Tool

decoder -- encode, decode, hash, transform, and generate payloads.

Actions: encode, decode, chain, analyze, reencode, jwt_decode, jwt_forge, polyglot, operations

smart_decode -- auto-detect and decode encoding chains layer by layer.

Actions: detect, auto_decode, detect_and_decode, encodings

Comparer

Comparer measures the difference between two HTTP responses. It is the foundation for differential testing -- detecting blind SQL injection, blind XSS, and other vulnerabilities where the application produces subtly different output depending on the injected value.

How It Works

Comparer uses the Gestalt Pattern Matching algorithm to compute a similarity ratio between 0.0 (completely different) and 1.0 (identical). It operates on response body text after applying normalization options.

Beyond the similarity ratio, Comparer identifies specific differences and categorizes them:

  • StatusCode -- the HTTP status codes differ
  • Header(name) -- a specific header value differs
  • Body(offset) -- a difference at an approximate character position in the body
  • BodyLength -- the bodies differ only in length
  • ResponseTime -- response times differ beyond a configurable threshold

Each difference has a type: Added, Removed, Changed, or LengthChange.

Comparison Options

  • normalize_whitespace (default: true) -- collapse whitespace before comparison; reduces noise from reformatted responses
  • ignore_case (default: false) -- case-insensitive comparison
  • excluded_headers -- headers excluded from comparison; by default: date, set-cookie, x-request-id, x-correlation-id, x-trace-id, etag, last-modified, age, expires
  • compare_timing (default: false) -- include response time in the diff
  • timing_threshold_ms (default: 1000) -- timing differences below this value are not flagged

Input Formats

Both left and right sides accept either:

  • A flow ID -- Comparer fetches the stored response from the database
  • Raw HTTP response text -- paste the full response including status line, headers, and body

You can mix the two: compare a stored flow against a freshly-pasted response.

Blind Injection Detection

The blind_detect action takes three responses: a baseline, a "true condition" response, and a "false condition" response. It computes:

  • true_similarity -- how similar the true response is to the baseline
  • false_similarity -- how similar the false response is to the baseline
  • similarity_gap -- the difference between the two scores

If the gap is large enough (true response very similar to baseline, false response noticeably different), is_vulnerable is set to true along with a confidence score.

Typical blind SQLi workflow

  1. Capture the baseline response to a normal request.
  2. Send a true-condition payload (e.g., AND 1=1) and capture that response.
  3. Send a false-condition payload (e.g., AND 1=2) and capture that response.
  4. Submit all three flow IDs to blind_detect.
  5. If is_vulnerable: true, Comparer has measured a statistically significant difference.

Similarity Score

The similarity ratio answers: what fraction of the content is shared between the two responses? A score of 1.0 means identical after normalization. A score of 0.0 means nothing is shared.

For blind injection testing, the relevant threshold is not the absolute values but the gap between the true and false conditions. The baseline anchors the comparison.

Lightweight Similarity

The similarity action accepts two flow IDs and returns only the similarity ratio without the full difference list. Use this when comparing large numbers of responses quickly and only the score matters.

MCP Tool

comparer -- response comparison for blind vulnerability detection.

Actions:

  • compare -- compare two responses by flow_id or raw content
  • blind_detect -- detect blind SQLi/XSS by comparing baseline/true/false responses
  • similarity -- calculate similarity score between two flows

API

POST /api/comparer/compare
{
  "left_flow_id": "uuid",
  "right_flow_id": "uuid",
  "options": {"normalize_whitespace": true, "ignore_case": false}
}

POST /api/comparer/blind-detect
{
  "baseline_flow_id": "uuid",
  "true_flow_id": "uuid",
  "false_flow_id": "uuid"
}

GET /api/comparer/similarity?left=uuid&right=uuid

Match and Replace

Match and Replace rules transform HTTP traffic as it flows through the proxy. Each rule is evaluated against every request or response in real time before the flow is stored or forwarded. Use this for quick, pattern-based modifications -- stripping headers, injecting values, or rewriting URLs on the fly.

Rule Structure

Every rule has:

  • name -- a label shown in the UI and logs
  • enabled -- toggle the rule on or off without deleting it
  • target -- which part of the traffic to match against
  • pattern -- the string or regular expression to find
  • replacement -- what to put in place of the match; empty string removes the matched content
  • is_regex -- if true, pattern is compiled as a regular expression and replacement may use capture group references ($1, $2, etc.)

Rules are applied in order. If a rule matches and modifies traffic, subsequent rules still run and may match on already-modified content.

Match Targets

Request targets (applied before the request is forwarded to the server):

  • request_header {name} -- matches the value of a specific request header (case-insensitive lookup). Only the value is modified, not the header name.
  • request_body -- matches the raw request body as UTF-8 text. Binary bodies are skipped.
  • request_url -- matches the full request URL string.
  • request_first_line -- matches the entire HTTP request line (method, path, version).

Response targets (applied before the response is forwarded to the browser):

  • response_header {name} -- matches the value of a specific response header.
  • response_body -- matches the response body as UTF-8 text.
  • response_first_line -- matches the HTTP response status line.

Additional operations available in Quick Rules:

  • Add request header -- inject a new header into outgoing requests
  • Remove request header -- strip a header from outgoing requests
  • Add response header -- inject a header into incoming responses
  • Remove response header -- strip a header from incoming responses

Literal vs Regex

With is_regex: false, the pattern is a literal string and every occurrence is replaced.

With is_regex: true, the pattern is compiled as a regular expression. All matches are replaced (equivalent to replace_all). If the regex is invalid, the rule is silently skipped.

Quick Rules vs Advanced Rules

The Match and Replace view has two tabs:

Quick Rules -- a flat, inline-editable table in the style of Burp's Match and Replace panel. Each row is a single match/replace pair with a target type, pattern, replacement, and regex toggle. Best for simple modifications.

Advanced Rules -- full Intercept Rules with complex condition logic, multiple conditions per rule, and multi-action support. See Intercept Rules for the full reference.

Practical Examples

Strip the Authorization header from all requests (test unauthenticated behavior):

{
  "target": "request_header",
  "name": "Authorization",
  "pattern": ".*",
  "replacement": "",
  "is_regex": true
}

Replace a CORS origin:

{
  "target": "request_header",
  "name": "Origin",
  "pattern": "https://attacker.com",
  "replacement": "https://trusted.example.com",
  "is_regex": false
}

Remove Content Security Policy from responses:

{
  "target": "response_header",
  "name": "Content-Security-Policy",
  "pattern": ".*",
  "replacement": "",
  "is_regex": true
}

Rewrite API version in URLs:

{
  "target": "request_url",
  "pattern": "/api/v1/",
  "replacement": "/api/v2/",
  "is_regex": false
}

Integration with the Plugin Bus

Match and Replace is implemented as a plugin in the proxy pipeline. On each request, the plugin iterates all enabled request-targeting rules. On each response, it iterates response-targeting rules. Rules are loaded from the store on startup and can be updated at runtime without restarting the proxy.

API

GET    /api/match-replace/rules
POST   /api/match-replace/rules          Create a rule
PUT    /api/match-replace/rules/{id}     Update a rule
DELETE /api/match-replace/rules/{id}     Delete a rule
POST   /api/match-replace/rules/{id}/toggle  Enable/disable

Session Rules

Session Rules automate token management across testing sessions. Instead of manually updating Authorization headers or cookies every time a session expires, you define rules that extract tokens from responses and inject them into subsequent requests automatically.

The Problem

Penetration tests often last hours. Session tokens expire. Every time you need to re-authenticate, you interrupt your workflow. Session Rules solve this by detecting expiration, triggering a re-authentication macro, and propagating new tokens forward without manual intervention.

Rule Structure

Each session rule contains:

  • name -- a label for the rule
  • scope -- a scope pattern limiting which URLs this rule applies to (host wildcard, URL prefix, or regex)
  • validation -- optional configuration for detecting invalid sessions
  • reauth_macro -- optional UUID of a macro to execute when the session expires
  • token_updates -- list of extraction + injection pairs (where to find the token, where to put it)
  • enabled / priority -- toggle and ordering; higher priority rules are evaluated first

Detecting Session Expiry

Validation checks detect when a session is no longer valid:

  • StatusCode -- response status is in a given list (e.g., [401, 403]); the most common check
  • ResponseContains -- response body contains a string (e.g., "session expired")
  • ResponseNotContains -- response body no longer contains an expected string (e.g., "authenticated")
  • HeaderContains -- a specific header contains a pattern
  • Regex -- a regex matches the response

One check type is active per rule.

Token Sources

Where to extract a token from the response:

  • ResponseBody(regex) -- regex with one capture group; the captured group is the token
  • ResponseHeader(header_name, regex) -- token extracted from a response header using a regex
  • Cookie(cookie_name) -- token is the value of a Set-Cookie header with the given name

Token Targets

Where to inject the extracted token into subsequent requests:

  • RequestHeader(header_name) -- sets the value of the named request header
  • Cookie(cookie_name) -- sets the value of the named cookie in the Cookie header
  • QueryParam(param_name) -- sets the value of a URL query parameter

Built-in Presets

Four preset rules cover the most common patterns:

JWT Bearer auth -- detects 401/403 as invalid, extracts access_token from JSON response body, injects into Authorization header as Bearer <token>.

Cookie-based session -- detects 302/401/403, extracts the named cookie from Set-Cookie, injects into Cookie header.

CSRF token -- extracts the CSRF token from a hidden input field (<input name="_csrf" value="...">), injects into the named request header.

OAuth2 refresh -- detects 401, triggers the macro to get a new access token, extracts both access_token and refresh_token from the response body.

How It Works

The session plugin hooks into the proxy pipeline:

  • On response -- extracts tokens from every matching response and caches them in memory. If a response indicates session expiry, the plugin flags the macro for execution.
  • On request -- if cached tokens exist, injects them into outgoing requests matching the rule scope.

Both auto-extract and auto-inject are enabled by default and can be disabled independently.

Cached tokens are held in a thread-safe map keyed by token name. Each new extraction overwrites the previous value, so token rotation is handled transparently.

Configuration Example

{
  "rules": [
    {
      "name": "API Auth",
      "scope": {"pattern": "*.api.example.com", "target": "host"},
      "validation": {
        "check_type": {"type": "StatusCode", "value": [401]}
      },
      "reauth_macro": "uuid-of-login-macro",
      "token_updates": [
        {
          "token_name": "access_token",
          "source": {"type": "ResponseBody", "regex": "\"access_token\":\"([^\"]+)\""},
          "target": {"type": "RequestHeader", "name": "Authorization"}
        }
      ],
      "enabled": true,
      "priority": 100
    }
  ],
  "auto_extract": true,
  "auto_inject": true
}

MCP Tool

session -- session and authentication management.

Actions:

  • tokens -- list currently cached tokens
  • status -- session manager status
  • list_macros -- list login macros
  • create_macro -- create a new login macro
  • get_macro -- get a specific macro
  • delete_macro -- remove a macro
  • execute_macro -- run a macro manually
  • refresh -- force token refresh

Intercept Rules

Intercept Rules is an automated traffic processing engine. Whereas the manual intercept queue requires you to be watching, Intercept Rules evaluate every flow silently in the background and apply actions automatically: forwarding, dropping, modifying headers, flagging for review, or queuing for manual inspection.

Rule Structure

Each rule has:

  • name / description -- labels for the UI and export
  • enabled -- toggle without deleting
  • priority -- higher values run first; rules are evaluated in priority order
  • group -- optional string for organizing rules into named profiles
  • conditions -- list of conditions to evaluate
  • condition_logic -- And (all must match) or Or (any must match)
  • action -- what to do when conditions are satisfied
  • apply_to -- Request, Response, or Both

Conditions

Each condition specifies:

  • field -- what to inspect
  • operator -- how to compare
  • value -- the comparison value
  • case_sensitive (default: false)
  • negate -- if true, the condition is satisfied when the match fails (NOT logic)

Match Fields

  • Host -- the request hostname
  • Path -- the URL path component
  • Url -- the full URL
  • Method -- HTTP method (GET, POST, etc.)
  • StatusCode -- response status code (as string)
  • Header(name) -- value of a named header
  • RequestBody -- request body text
  • ResponseBody -- response body text
  • ContentType -- value of the Content-Type header
  • ContentLength -- value of the Content-Length header (for numeric comparisons)
  • Cookie(name) -- value of a named cookie
  • QueryParam(name) -- value of a named URL query parameter
  • Any -- matches anywhere in the entire request or response; useful with Exists to unconditionally trigger

Match Operators

  • Contains -- substring match
  • NotContains -- substring absence
  • Equals -- exact match
  • NotEquals -- exact non-match
  • StartsWith -- prefix match
  • EndsWith -- suffix match
  • Regex -- full regular expression
  • LessThan / GreaterThan -- numeric comparison
  • Exists -- the field exists regardless of value
  • NotExists -- the field does not exist

Actions

  • Forward -- let traffic pass unchanged (useful as a default catch-all)
  • Drop -- block the request or response; the client receives an error
  • Intercept -- add the flow to the manual intercept queue for pause-and-inspect
  • Modify(modifications) -- apply modifications and forward
  • Flag {color, note} -- tag the flow with a color and optional note; does not block traffic
  • Log {message} -- write a log entry; does not block traffic
  • Multi(actions) -- execute multiple actions in sequence (e.g., flag and modify)

Modifications

A Modify action takes a list of modification objects.

Targets:

  • Header(name) -- a request or response header
  • QueryParam(name) -- a URL query parameter
  • Cookie(name) -- a cookie value
  • Body -- the request or response body
  • Path -- the URL path
  • Method -- the HTTP method
  • StatusCode -- the response status code
  • Host -- the request hostname

Operations:

  • Set(value) -- replace the entire field value
  • Remove -- delete the field entirely
  • Replace {find, replace, regex} -- find-and-replace within the current value
  • Append(value) -- append to the current value
  • Prepend(value) -- prepend to the current value

Rule Groups

Rules are organized into named groups. A group has an enabled flag -- disabling a group disables all its rules at once. This makes it easy to switch between testing profiles (e.g., enable a "No Auth" group that strips authorization headers, disable it when done).

Built-in Presets

Ready-to-use rules that cover common testing scenarios:

  • block_trackers() -- drops requests to analytics and tracking domains (google-analytics, doubleclick, etc.)
  • flag_credentials() -- flags requests with Authorization headers, login-path URLs, or body fields containing password/token/api_key
  • strip_security_headers() -- removes CSP, X-Frame-Options, HSTS, X-Content-Type-Options, and X-XSS-Protection from responses
  • add_header(name, value) -- injects a header into all requests
  • custom_user_agent(ua) -- replaces the User-Agent on all requests
  • intercept_logins() -- queues requests to login/auth paths for manual inspection
  • flag_api_keys() -- flags responses containing AWS access keys, Stripe secret keys, or generic API key patterns
  • highlight_json() -- flags JSON responses with a blue color
  • flag_large_responses(size_bytes) -- flags responses larger than the given byte count
  • block_file_types(extensions) -- drops requests for named file extensions (e.g., png, jpg, css)

Examples

Inject a testing header into every request:

{
  "name": "Add X-Test-Mode",
  "enabled": true,
  "priority": 10,
  "conditions": [{"field": "Any", "operator": "Exists", "value": ""}],
  "condition_logic": "And",
  "action": {"Modify": [{"target": {"Header": "X-Test-Mode"}, "operation": {"Set": "1"}}]},
  "apply_to": "Request"
}

Drop static assets:

{
  "name": "Block Static",
  "enabled": true,
  "priority": 50,
  "conditions": [{"field": "Path", "operator": "Regex", "value": "\\.(css|js|png|jpg|gif|woff2)$"}],
  "condition_logic": "And",
  "action": "Drop",
  "apply_to": "Request"
}

Flag responses over 1 MB:

{
  "name": "Large Response",
  "enabled": true,
  "priority": 5,
  "conditions": [{"field": "ContentLength", "operator": "GreaterThan", "value": "1048576"}],
  "condition_logic": "And",
  "action": {"Flag": {"color": "orange", "note": "Large response"}},
  "apply_to": "Response"
}

MCP Tool

rules -- manage intercept rules.

Actions:

  • list -- list all rules
  • get -- get a rule by ID
  • create -- create a new rule (requires name, conditions, rule_action)
  • update -- modify an existing rule
  • delete -- remove a rule
  • groups_list -- list rule groups
  • groups_create -- create a new group
  • groups_delete -- delete a group

WebSocket

Hugin captures, stores, and lets you inspect and manipulate WebSocket traffic bidirectionally. Every frame flowing through the proxy is recorded with direction, type, payload, and timestamp.

How Capture Works

When the proxy receives an HTTP request with Upgrade: websocket, it hands the connection to the WebSocket manager. The original HTTP 101 handshake is recorded as a flow in the usual history. All subsequent frames are stored as WebSocket messages linked to that flow.

The proxy runs two concurrent relay tasks per connection: one for client-to-server frames, one for server-to-client frames. Each frame passes through a capture and optional interception step before being forwarded.

Frame Types

All WebSocket frame opcodes are tracked:

  • Text -- UTF-8 text payload, previewed in the UI
  • Binary -- raw bytes, displayed as hex or byte count
  • Ping -- keepalive sent by either side
  • Pong -- keepalive reply
  • Close -- connection termination frame with optional close code and reason

Connection Lifecycle

When an upgrade completes, a WebSocket connection is registered:

  • id -- UUID for the connection
  • flow_id -- links to the original HTTP 101 flow
  • url / host -- the WebSocket endpoint
  • message_count -- incremented on each captured frame
  • state -- Open, Closing, or Closed

Active connections are held in memory. When a connection closes, the database record is updated with the close timestamp.

Message Storage

Each captured message is persisted with:

  • Connection ID
  • Direction (ClientToServer or ServerToClient)
  • Opcode
  • Payload bytes
  • Timestamp

Messages are queryable by connection ID, direction, and time range.

Real-time Streaming

The manager provides two broadcast channels for live updates:

  • A message channel emitting each captured frame -- the UI and event stream receive frames in real time
  • A connection channel emitting connect and disconnect events

Both channels are buffered (1,000 messages, 100 connections). Slow consumers miss old messages but never block the proxy.

The MCP tool supports streaming via poll_messages and poll_connections actions with since_id or since parameters for incremental polling.

Manual Intercept

WebSocket intercept works like HTTP intercept. When enabled, each frame is held in a pending queue before being forwarded. You can:

  • Forward -- release the frame unchanged
  • Forward Modified -- change the opcode and/or payload before forwarding
  • Drop -- discard the frame; neither side receives it

Each pending message shows direction, opcode, full payload, and timestamp. The UI previews the first 200 characters for text frames or a byte count for binary frames.

Message Injection

Inject arbitrary frames into any active WebSocket connection from outside the browser:

POST /api/websocket/{connection_id}/send
{
  "opcode": "Text",
  "payload": "{\"action\": \"subscribe\", \"channel\": \"admin\"}"
}

The payload is forwarded to the server as if it originated from the browser. Binary payloads are accepted as Base64-encoded bytes.

Injection only works while the connection is active. Sending to a closed connection returns a 404.

Listing Connections and Messages

GET /api/websocket/connections
GET /api/websocket/connections/{id}
GET /api/websocket/connections/{id}/messages?direction=client_to_server&limit=100

Active connections show closed_at: null. Historical connections include the close timestamp.

Use Cases

  • Protocol reverse engineering -- capture and inspect the message format before crafting modified payloads
  • Privilege escalation -- inject messages the UI never sends (admin actions, restricted channel subscriptions)
  • Message tampering -- intercept a frame mid-flight and change amounts, IDs, or action names
  • Replay attacks -- send stored messages to test idempotency or re-trigger server-side actions
  • State manipulation -- drop specific frames to test how the application handles missing messages

MCP Tool

websocket -- WebSocket traffic inspection and manipulation.

Actions:

  • connections -- list all WebSocket connections
  • get -- get a specific connection by ID
  • messages -- list messages for a connection (filter by direction, limit)
  • send -- inject a message into an active connection
  • delete -- delete a connection record
  • poll_messages -- stream new messages (with since_id or since for incremental polling)
  • poll_connections -- stream new connection events
  • intercept_status -- check if WebSocket intercept is enabled
  • intercept_toggle -- enable or disable WebSocket intercept
  • intercept_list -- list pending intercepted frames
  • intercept_get -- get a specific pending frame
  • intercept_forward -- forward a pending frame
  • intercept_drop -- drop a pending frame
  • intercept_forward_all -- forward all pending frames
  • intercept_drop_all -- drop all pending frames

Synaps Scanner

Synaps is Hugin's WASM-based vulnerability scanner. Modules are compiled to WebAssembly and executed in a sandboxed runtime (Wasmtime), providing safe, portable, and extensible scanning. Each module runs with a 1 billion instruction fuel limit and a 16 MB memory cap. A misbehaving or malicious module cannot hang the scanner or consume unbounded resources.

How It Works

  1. Modules are written in Rust and compiled to wasm32-unknown-unknown.
  2. At scan time, Hugin loads modules and feeds them target information.
  3. Each module decides whether to check a target (should_check) and performs its analysis (check).
  4. Modules can make HTTP requests, DNS queries, raw TCP connections, WebSocket connections, and browser automation calls through the host runtime.
  5. Results (findings) are collected and stored in the database.

Module Lifecycle

get_info()      -> Returns module metadata (name, severity, tags, CVE, CWE, CVSS)
should_check()  -> Returns true/false based on target characteristics
check()         -> Performs the actual vulnerability check

Host Capabilities

Modules interact with the outside world exclusively through the Context trait. The host brokers all calls. Available capabilities:

  • HTTP -- GET, POST, and custom requests with headers and bodies
  • DNS -- A/AAAA/TXT queries
  • TLS -- Certificate inspection
  • Raw TCP -- Arbitrary TCP connections with timeout control
  • WebSocket -- Connect, send, receive, close
  • OOB (Oastify) -- Generate DNS/HTTP/SMTP/LDAP/FTP/SMB callback payloads and check for triggers
  • Headless browser -- Navigate, inspect DOM, fill forms, click, screenshot
  • Inter-module data -- Share data between producer and consumer modules
  • Logging -- Debug, info, warn messages

Module Workflows (Producer/Consumer)

Modules can form pipelines. A producer module sets is_producer: true in its metadata and stores data for downstream modules via set_shared_data(). Consumer modules declare dependencies and retrieve that data via get_shared_data() and get_module_result(). The runtime respects execution order: producers run first.

Managing Modules

CLI

# Download/update community modules
hugin scanner update

# List installed modules
hugin scanner list

# Install a specific module
hugin scanner install ai-gateway-detect

# Remove a module
hugin scanner remove example-module

MCP Tool: synaps

The synaps MCP tool provides full module management and scanning. Requires a Pro license.

Core actions:

  • list -- Show installed modules. Filter by tags, severity, cve.
  • info -- Get detailed metadata for a specific module.
  • scan -- Run one or more modules against a target.
  • validate -- Check that a .wasm binary has valid exports.
  • stats -- Module database statistics.
  • tags -- List all tags across modules.
  • search -- Find modules by keyword.

Module-specific scans (run a single specialized check):

  • scan_ai_gateway -- AI gateway fingerprinting
  • scan_ai_ssrf -- AI agent SSRF detection
  • scan_bare_lf -- Bare LF HTTP request smuggling
  • scan_cache_poison -- Cache poisoning
  • scan_charset_rce -- Charset-based RCE
  • scan_fluentbit -- Fluent Bit CVE detection
  • scan_graphql_intro -- GraphQL introspection
  • scan_graphql_sub -- GraphQL subscription endpoint checks
  • scan_grpc_web -- gRPC-Web endpoint detection
  • scan_jwt_confusion -- JWT algorithm confusion
  • scan_mass_assign -- Mass assignment
  • scan_mqtt -- MQTT protocol analysis
  • scan_nextjs_csrf -- Next.js CSRF token bypass
  • scan_oidc -- OIDC logout endpoint detection
  • scan_quic -- QUIC protocol fingerprinting
  • scan_rust_http -- HTTP differential response analysis
  • scan_rust_panic -- Rust panic endpoint detection
  • scan_ssrf -- Server-side request forgery
  • scan_vectordb -- Vector database endpoint detection
  • scan_wcd -- Web cache deception
  • scan_webtransport -- WebTransport endpoint detection

Community Modules

The synaps-community repository contains community-contributed modules organized by category:

  • web -- Web framework vulnerabilities (Next.js, GraphQL, HTTP smuggling)
  • cloud -- Cloud service misconfigurations (AI gateways, FluentBit CVEs)
  • api -- API security issues (OAuth, OIDC)
  • injection -- Injection vulnerabilities (charset RCE)
  • cve -- Known CVE detection
  • tech -- Technology fingerprinting (AI agents, vector DBs, MQTT, QUIC)

See Community Modules for details on installing and updating community modules, and Module Development for the complete guide to writing your own.

Writing Synaps WASM Modules

Synaps modules are Rust crates that compile to wasm32-unknown-unknown and run inside Hugin's sandboxed WASM runtime. Each module is an isolated, independently deployable vulnerability check. The sandbox enforces a 1 billion instruction fuel limit and a 16 MB memory cap.

Project Setup

cargo new --lib my-check
cd my-check

Set the crate type in Cargo.toml:

[lib]
crate-type = ["cdylib"]

[dependencies]
hugin-synaps-guest = { path = "../../hugin-scanner-guest" }
serde_json = "1"

Add a .cargo/config.toml to set the default target:

[build]
target = "wasm32-unknown-unknown"

Module Structure

Every module needs three functions wired together with the synaps_module! macro: get_info, check, and optionally should_check.

use hugin_synaps_guest::prelude::*;

fn get_info() -> ModuleInfo {
    ModuleInfo {
        id: "my-vuln-check".into(),
        name: "My Vulnerability Check".into(),
        author: "yourname".into(),
        description: "Detects XYZ misconfiguration".into(),
        severity: Severity::High,
        tags: vec!["web".into(), "misconfig".into()],
        cve: Some("CVE-2024-1234".into()),
        cwe: Some(vec!["CWE-16".into()]),
        cvss: Some(7.5),
        references: vec!["https://example.com/advisory".into()],
        dependencies: vec![],
        is_producer: false,
    }
}

fn should_check(target: &TargetInfo) -> bool {
    target.scheme == "https"
}

fn check<C: Context>(ctx: &C, target: &TargetInfo) -> Result<CheckResult, CheckError> {
    let resp = ctx.http_get("/api/status")?;

    if resp.status == 200 && resp.contains("debug_mode: true") {
        return Ok(CheckResult::vulnerable(Confidence::High)
            .with_evidence(Evidence::http_response(resp.body_str().unwrap_or("")))
            .with_message("Debug mode enabled on production endpoint"));
    }

    Ok(CheckResult::not_vulnerable())
}

synaps_module!(
    info: get_info,
    check: check,
    should_check: should_check
);

The Context Trait

The Context trait is the module's interface to the host. It provides every capability the module needs without direct network or filesystem access -- the runtime brokers all calls.

HTTP

// Simple GET
let resp = ctx.http_get("/path")?;

// Custom request with headers
let req = HttpRequest::get("/api/data")
    .with_header("X-Custom", "value")
    .with_header("Accept", "application/json");
let resp = ctx.http_request(&req)?;

// POST with body
let resp = ctx.http_post("/submit", b"{\"key\":\"value\"}".to_vec())?;

// Inspect response
println!("Status: {}", resp.status);
println!("Body: {}", resp.body_str().unwrap_or(""));
println!("Header: {}", resp.header("content-type").unwrap_or(""));

DNS and TLS

let dns = ctx.dns_query(&DnsQuery::a("target.example.com"))?;
let first_ip = dns.first_value();

let tls = ctx.tls_info("target.example.com", 443)?;
let cert = tls.certificate.as_ref();

Raw TCP

let req = TcpRequest::new("target.example.com", 8080, b"PING\r\n".to_vec())
    .with_timeout(3000);
let resp = ctx.tcp_request(&req)?;
let data = resp.data_str().unwrap_or("");

WebSocket

let conn = ctx.ws_connect("wss://target.example.com/ws")?;
ctx.ws_send_text(conn, r#"{"action":"ping"}"#)?;
let msg = ctx.ws_recv(conn, 5000)?;
ctx.ws_close(conn)?;

OOB (Oastify) Payloads

let payload = ctx.oastify_dns(Some("my-check"))?;
// Inject payload.payload into the target
// ...
// Wait and check for callback
if ctx.oastify_was_triggered(&payload.correlation_id) {
    return Ok(CheckResult::vulnerable(Confidence::Confirmed)
        .with_message("OOB DNS interaction received"));
}

Headless Browser

ctx.browser_navigate("https://target.example.com/login", 2000)?;
let dom = ctx.browser_get_dom()?;
if dom.has_form_action("/submit") {
    ctx.browser_input("#username", "test")?;
    ctx.browser_click("#submit")?;
}
let screenshot = ctx.browser_screenshot()?;

Logging

ctx.debug("Checking endpoint /api");
ctx.info("Found suspicious header");
ctx.warn("Unexpected response status");

Severity and Confidence

Severity maps to CVSS scores when from_cvss() is used: Critical (9.0+), High (7.0+), Medium (4.0+), Low (0.1+). Set it in get_info.

Confidence on CheckResult has four levels:

  • Confirmed -- OOB callback proof or definitive evidence. Use only when you have Oastify or equivalent confirmation.
  • High -- Direct response evidence (error messages, math evaluation, file contents).
  • Medium -- Differential signals (response differs from baseline).
  • Low -- Heuristic or indirect signals.

Module Workflows (Producer/Consumer)

Modules can form pipelines. A producer module sets is_producer: true and stores data for downstream modules:

// Producer module
ctx.set_shared_data("discovered_api_key", &api_key)?;

Consumer modules declare dependencies and retrieve that data:

// In get_info
dependencies: vec!["my-producer-module".into()],

// In check
let api_key = ctx.get_shared_data("discovered_api_key")?;
let result = ctx.get_module_result("my-producer-module")?;
if let Some(r) = result {
    if r.is_vulnerable() {
        // Build on the producer's finding
    }
}

Building

cargo build --target wasm32-unknown-unknown --release

The output is at target/wasm32-unknown-unknown/release/my_check.wasm.

Testing Without WASM

The guest SDK ships a MockContext for native unit tests. The macros compile correctly for native targets and use MockContext automatically:

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_module_info() {
        let info = get_info();
        assert_eq!(info.severity, Severity::High);
        assert!(!info.id.is_empty());
    }

    #[test]
    fn test_should_check_https_only() {
        let target = TargetInfo {
            scheme: "https".into(),
            host: "example.com".into(),
            ..Default::default()
        };
        assert!(should_check(&target));

        let http_target = TargetInfo { scheme: "http".into(), ..target };
        assert!(!should_check(&http_target));
    }
}

Run native tests with:

cargo test

Installing a Built Module

Copy the .wasm file into the Hugin modules directory or use the synaps MCP tool with the scan action pointing to a local path. The runtime validates the WASM magic bytes and exports before loading.

Community Modules

Community modules are Synaps WASM checks distributed through the Hugin module registry. They are sandboxed by the Wasmtime runtime -- each module runs with a 1 billion instruction fuel limit and 16 MB memory cap. A misbehaving or malicious module cannot affect the host process.

How Modules Are Stored

Installed modules live on disk in the Hugin modules directory. Each module is represented by two files:

{modules_dir}/
  {module-id}.wasm    -- compiled WASM binary
  {module-id}.json    -- metadata (version, checksum, install timestamp)

The metadata file records the module ID, name, version, category, severity, SHA256 checksum, and installation time. If the .json file is present but the .wasm is missing, the entry is skipped at load time.

The Catalog Format

The registry catalog is a JSON document served from a remote URL (typically a GitHub raw URL). Each entry includes all fields needed for display, filtering, and downloading. The wasm_filename is used to construct the download URL: {base_url}/modules/{category}/{wasm_filename}.

Installing Modules

Use the synaps MCP tool or the Hugin UI scanner panel. The install flow:

  1. Fetch the remote catalog from the configured registry URL.
  2. Compare against locally installed versions.
  3. Download the WASM binary for each new or updated module.
  4. Compute the SHA256 of the downloaded bytes and verify it against the expected checksum from the catalog (when a checksum is provided).
  5. Write the .wasm and .json files to the modules directory.

If a module with the same ID already exists, the install overwrites both files.

CLI

hugin scanner update          # Fetch catalog and install new/updated modules
hugin scanner list            # List installed modules
hugin scanner install <name>  # Install a specific module
hugin scanner remove <name>   # Remove a module

Updating Modules

The diff logic compares catalog entries against locally installed modules by ID and version string. A module is marked for update when the catalog version differs from the installed version. New modules (IDs not present locally) are also included in the update list and tagged [NEW]. Updated modules show their previous version alongside the new version as [UPD].

Filtering at Load Time

When the scanner loads modules for a run, it filters by:

  • Module ID (explicit allowlist via enabled_checks in scan config -- empty means all).
  • Whether the module's declared applicable_locations intersect with the target's insertion points.
  • The should_check export -- the module itself can reject a target based on scheme, technologies, or metadata before any network request is made.

Module Dependencies

Some modules declare dependencies on other modules via the dependencies array in their ModuleInfo. The runtime respects execution order: producer modules run first, then consumers can read their extracted data via get_module_result() and get_shared_data(). A module marked is_producer: true is expected to write shared data for downstream modules.

Available Community Modules

The current synaps-modules directory includes the following modules:

  • example -- Directory listing detection (reference implementation)
  • nextjs-csrf -- Next.js CSRF token bypass detection
  • oidc-logout-detect -- OIDC logout endpoint detection
  • quic-fingerprint -- QUIC protocol fingerprinting
  • webtransport-detect -- WebTransport endpoint detection
  • bare-lf-smuggling -- Bare LF HTTP request smuggling
  • rust-panic -- Rust panic endpoint detection
  • rust-http-diff -- HTTP differential response analysis
  • graphql-subscription -- GraphQL subscription endpoint checks
  • charset-rce -- Charset-based RCE detection
  • mqtt-analyze -- MQTT protocol analysis
  • grpc-web-detect -- gRPC-Web endpoint detection
  • ai-gateway-detect -- AI gateway fingerprinting
  • fluentbit-cve -- Fluent Bit CVE detection
  • ai-agent-ssrf -- AI agent SSRF detection
  • oauth-misconfig -- OAuth misconfiguration checks
  • vector-db-detect -- Vector database endpoint detection

Integrity Verification

Every module download computes a SHA256 hash of the raw WASM bytes. When the recommended download path is used, the computed hash must match the expected checksum from the catalog exactly. A mismatch returns a checksum error and the module is not installed.

Removing a Module

Removing a module deletes both its .wasm binary and .json metadata file. If only one file exists, it is still removed. Attempting to remove a module that does not exist returns a not-found error.

Active Scanner

The active scanner is the built-in engine that replays captured flows with attack payloads and analyzes responses for vulnerabilities. It operates on HttpFlow records -- requests you have already captured through the proxy. It does not crawl or discover endpoints on its own; it tests what you have already seen.

The 43 Active Checks

All checks are registered at startup. Each has a string ID used for filtering.

Injection

  • active-sqli -- SQL Injection. Error-based (15+ SQL error signatures), time-based (5s delay via SLEEP/pg_sleep/WAITFOR), differential (baseline comparison).
  • active-xss -- Cross-Site Scripting. Reflected payload patterns across HTML body, attribute, JS, and URL contexts.
  • active-stored-xss -- Stored/Blind XSS. Injects callback payloads that fire on later page views. OOB confirmation.
  • active-cmdi -- OS Command Injection. Error strings, time delays, OOB callbacks.
  • active-ssti -- Server-Side Template Injection. Math evaluation ({{7*7}} -> 49) across Jinja2, Twig, Freemarker, Velocity, Pebble, Mako, Smarty engines.
  • active-ssjs -- Server-Side JavaScript Injection. Node.js eval() and Function() injection patterns.
  • active-el-injection -- Expression Language Injection. Java EL (${7*7}), Spring SpEL, OGNL injection.
  • active-xpath-injection -- XPath Injection. Boolean-based and error-based payloads.
  • active-ldap-injection -- LDAP Injection. Special characters, wildcard injection, OOB callbacks via JNDI.
  • active-nosql -- NoSQL Injection. MongoDB operator injection ($gt, $ne, $regex), JavaScript injection in $where.
  • active-xml-injection -- XML Injection. Entity expansion, attribute injection, CDATA breakout.
  • active-xxe -- XML External Entity. OOB exfiltration, file content patterns (root:, [boot loader]), parameter entities.
  • active-email-injection -- Email Header Injection. CRLF injection in email headers, BCC/CC injection.
  • active-header-injection -- HTTP Response Splitting. CRLF injection in response headers.

Authentication and Authorization

  • active-csrf -- Cross-Site Request Forgery. Missing token detection, origin header bypass, SameSite cookie analysis.
  • active-jwt -- JWT Attacks. none algorithm, HS/RS confusion, JKU/X5U hijack, key brute-force.
  • active-bola -- BOLA/IDOR. Numeric ID enumeration, UUID swapping, path-based object reference testing.
  • active-session-fixation -- Session Fixation. Pre-authentication session token reuse detection.
  • active-oauth -- OAuth/OIDC Active Testing. Redirect URI manipulation, state parameter bypass, PKCE downgrade, token leakage.
  • active-keycloak -- Keycloak IAM Misconfiguration. Realm enumeration, token endpoint exposure, well-known endpoint checks.
  • active-mass-assignment -- Mass Assignment. Admin flag injection (isAdmin, role, privilege), hidden field discovery.
  • active-graphql-authz -- GraphQL Authorization Bypass. Field-level access control testing, introspection-based permission probing.

Request Smuggling and Desync

  • active-http-smuggling -- HTTP Request Smuggling. CL.TE, TE.CL, TE.TE timing differential detection.
  • active-csd -- Client-Side Desync. Browser-based request smuggling gadgets, connection reuse exploitation.
  • active-http2 -- HTTP/2 Specific Attacks. H2.CL desync, HPACK bomb, pseudo-header injection, stream multiplexing abuse.

Cache and Redirect

  • active-cache-poisoning -- Web Cache Poisoning. Unkeyed header injection, X-Forwarded-Host, X-Original-URL, poisoned response caching verification.
  • active-cache-deception -- Web Cache Deception. Path confusion attacks, extension appending, delimiter injection to cache sensitive responses.
  • active-open-redirect -- Open Redirect. Protocol-relative URLs, double-URL encoding, backslash tricks, domain confusion.

Server-Side

  • active-ssrf -- Server-Side Request Forgery. OOB callback domain, cloud metadata URLs (169.254.169.254), DNS rebinding, protocol smuggling.
  • active-deserialization -- Insecure Deserialization. Java ysoserial patterns, .NET formatters, PHP unserialize(), Python pickle. OOB callbacks.
  • active-race-condition -- Race Condition. Concurrent request divergence detection.
  • active-file-upload -- File Upload Vulnerability. Extension bypass, content-type mismatch, polyglot files, double extension, null byte injection.

Prototype Pollution

  • active-prototype-pollution -- Client-Side Prototype Pollution. __proto__ and constructor.prototype injection via query, body, and JSON.
  • active-ss-prototype-pollution -- Server-Side Prototype Pollution. Status code differential, JSON reflection, delayed effect detection.

Protocol and Method

  • active-websocket -- WebSocket Security. Upgrade bypass, CSWSH (cross-site WebSocket hijacking), message injection, origin validation.
  • active-graphql -- GraphQL Injection. Introspection leak, query batching, field suggestion leakage, alias-based DoS.
  • active-host-header -- Host Header Injection. Password reset poisoning, web cache poisoning via Host, X-Forwarded-Host, absolute URL override.
  • active-method-override -- HTTP Method Override. X-HTTP-Method-Override, X-Method-Override, _method parameter for access control bypass.
  • active-http-method -- HTTP Method Testing. OPTIONS enumeration, PUT/DELETE access, TRACE XST.
  • active-hpp -- HTTP Parameter Pollution. Duplicate parameter injection to bypass WAF rules and server-side validation.
  • active-cors -- CORS Misconfiguration. Origin reflection, null origin, subdomain wildcard, credential inclusion with permissive origins.

Insertion Points

The scanner automatically extracts injection points from each flow:

  • QueryParam -- every key=value pair in the query string
  • BodyParam -- form-urlencoded body fields
  • JsonField -- all string values in JSON bodies, including nested paths (e.g. json[data.user.id])
  • Header -- User-Agent, Referer, X-Forwarded-For, Authorization, and custom X-* headers
  • Cookie -- each individual cookie name-value pair
  • UrlPath -- path segments
  • XmlElement -- XML body (for XXE; the check replaces the full body)

For each extracted point, the scanner runs the TransformEngine to detect nested encodings. If a parameter value is Base64-encoded JSON, the payload is re-encoded through the same transform chain before injection. This happens transparently.

Detection Modes

Each payload carries an ExpectedBehavior that determines how the response is analyzed:

Error-based -- looks for a specific pattern string in the response body. SQL error messages, stack traces, template math output.

Time-based -- triggers if response time meets or exceeds a threshold in milliseconds. The default time-based SQL injection threshold is 5000ms.

Differential -- compares the response against a cached baseline for the same insertion point. The first request to a given point becomes the baseline. Subsequent payloads are compared using ResponseComparator. A similarity score below 0.85 (85%) flags a finding.

Out-of-band -- sends a payload containing the configured callback domain and marks it as triggered immediately. Actual OOB confirmation happens asynchronously through Oastify or an external collaborator.

Scan Profiles

Five predefined profiles configure the scanner for different assessment needs:

Quick -- Fewer payloads (max 2 per insertion point), no time-based checks, no OOB, 10 concurrent requests, 15s timeout. For fast initial assessment.

Normal -- Default payload set, time-based enabled, OOB enabled, 5 concurrent requests, 30s timeout. Standard behavior.

Thorough -- All payloads (unlimited per point), extended timeouts (60s), retry on timeout, 3 concurrent requests. For deep assessment.

PassiveOnly -- No active probing. Only passive checks on observed traffic.

AuditOnly -- Active checks but non-invasive only. Skips SQLi DELETE payloads, file upload, and other destructive checks. Time-based and OOB enabled.

Scan Configuration

{
  "profile": "normal",
  "request_delay_ms": 100,
  "max_concurrency": 5,
  "timeout_secs": 30,
  "enabled_checks": [],
  "enabled_locations": [],
  "follow_redirects": false,
  "verify_ssl": true,
  "callback_domain": null,
  "max_payloads_per_point": 1000
}
  • profile -- One of quick, normal, thorough, passive_only, audit_only. Overrides individual settings.
  • enabled_checks -- List of check IDs to run. Empty means all 43 checks.
  • enabled_locations -- List of insertion location types to test. Empty means all applicable.
  • callback_domain -- Domain for OOB detection (SSRF, XXE, LDAP, JWT, deserialization, stored XSS). Without this, OOB checks fall back to error-based detection only.
  • max_payloads_per_point -- Caps the number of payloads per insertion point. Default is 1000; set to 0 for no limit.
  • request_delay_ms -- Per-host delay between requests. The rate limiter tracks the last request time per host independently.
  • max_concurrency -- Maximum parallel in-flight requests. Backed by a tokio semaphore.

Passive Checks (29 checks)

Passive checks analyze captured traffic without sending any requests. They run automatically on every flow.

Security Header Checks

  • security-headers -- Missing Security Headers. Checks for Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Permissions-Policy, Referrer-Policy.
  • hsts-detailed -- HSTS Detailed Analysis. Max-age too short, missing includeSubDomains, missing preload, HSTS on HTTP (useless).
  • csp-detailed -- CSP Detailed Analysis. unsafe-inline, unsafe-eval, wildcard sources, missing directives, overly permissive domains, base-uri missing.
  • clickjacking -- Clickjacking Protection Missing. No X-Frame-Options or frame-ancestors CSP directive on HTML responses.
  • referrer-policy -- Referrer-Policy Check. Missing or overly permissive policy that leaks URLs to third parties.
  • permissions-policy -- Permissions-Policy Check. Missing policy or overly permissive feature grants (camera, microphone, geolocation).

Information Disclosure

  • sensitive-data -- Sensitive Data Exposure. API keys, tokens, credentials in response bodies.
  • information-disclosure -- Information Disclosure. Server version headers, powered-by headers, debug information.
  • private-ip-disclosure -- Private IP Address Disclosure. RFC1918 addresses (10.x, 172.16-31.x, 192.168.x) in responses.
  • email-disclosure -- Email Address Disclosure. Email addresses in response bodies.
  • credit-card-disclosure -- Credit Card Number Disclosure. PAN patterns with Luhn validation.
  • stack-trace-disclosure -- Stack Trace Disclosure. Java, .NET, Python, PHP, Ruby, Node.js stack traces.
  • software-version-disclosure -- Software Version Disclosure. Library and framework versions in responses.
  • internal-path-disclosure -- Internal Path Disclosure. Server filesystem paths (/var/www, C:\inetpub, /home/).

Cookie and Session

  • cookie-security -- Insecure Cookie Configuration. Missing Secure, HttpOnly, SameSite attributes.
  • passive-session-token-url -- Session Token in URL. Session IDs passed via query parameters.
  • passive-cleartext-password -- Cleartext Password Submission. Passwords sent over HTTP.
  • passive-password-autocomplete -- Password Autocomplete. Password fields without autocomplete="off".

Content and Response

  • cors-misconfiguration -- CORS Misconfiguration. Overly permissive Access-Control-Allow-Origin, credential inclusion.
  • mixed-content -- Mixed Content. HTTPS pages loading HTTP resources (scripts, stylesheets, images).
  • content-type-mismatch -- Content-Type Mismatch. Response body type does not match Content-Type header.
  • sri-missing -- Missing Subresource Integrity. External scripts and stylesheets without SRI hashes.
  • cacheable-response -- Cacheable Sensitive Response. Sensitive endpoints returning cache-friendly headers.
  • directory-listing -- Directory Listing. Apache/Nginx/IIS directory indexes enabled.
  • open-redirect -- Open Redirect. Redirect responses pointing to user-controlled URLs.

Application Logic

  • oauth-flow -- OAuth/OIDC Flow Analysis. Missing state parameter, token in fragment, insecure redirect URIs.
  • deserialization-content-type -- Dangerous Deserialization Content Types. Java serialized objects, XML with DOCTYPE, YAML load, pickle in request/response.
  • passive-viewstate -- ViewState Analysis. Unencrypted or unsigned ASP.NET ViewState.

Reflection and Leakage

  • passive-input-reflection -- Input Reflection. Request parameters reflected unencoded in response body.
  • passive-referer-leak -- Cross-Domain Referer Leak. Sensitive URLs leaked to third-party domains via Referer header.
  • passive-sensitive-url -- Sensitive Data in URL. Passwords, tokens, API keys in query parameters.

MCP Tool: scanner

Actions:

  • start -- Start a scan with flow_ids and optional config.
  • status -- Current scan progress.
  • checks -- List all available active checks.
  • findings -- List findings from the current or a specific scan.
  • cancel / pause / resume -- Control an in-progress scan.
  • clear -- Clear all findings.
  • list_scans -- Scan history.
  • get_scan / delete_scan -- Individual scan management.
  • get_finding / delete_finding / update_finding -- Finding management.
  • audit_items -- Group findings by check ID for a specific scan.
  • create_finding -- Manually create a finding.
  • add_finding_flow / remove_finding_flow / list_finding_flows -- Associate flows with findings.
  • add_finding_tag / remove_finding_tag / list_finding_tags -- Tag findings.

Findings

Each finding records:

  • The check that produced it
  • The insertion point name and location
  • The payload that triggered the detection
  • The raw HTTP request with the payload injected
  • The raw HTTP response
  • Detection evidence (pattern matched, time delta, similarity score)
  • Severity inherited from the check

Findings are stored per-flow and queryable by flow ID, check ID, severity, or tag. The probe request/response (the exact traffic that produced the finding) is stored separately and retrievable for inclusion in reports.

OOB Callback Integration

When callback_domain is configured, checks that support OOB (SSRF, XXE, LDAP injection, JWT, deserialization, stored XSS) automatically include Oastify payloads. The scanner marks those findings as triggered immediately so they appear in the findings list. To confirm them, poll Oastify for the correlation ID embedded in the payload.

Checks without a callback_domain fall back to error-based detection only. OOB confirmation upgrades finding confidence to Confirmed.

Nerve -- Passive Parameter Intelligence

Nerve is a passive analysis engine that reads HTTP traffic and produces actionable intelligence about what to test. It does not send any requests. It reads parameter names and values from flows you have already captured and maps them to vulnerability categories using a signal database of 714 patterns across 21 categories.

What Nerve Does

Nerve answers two questions:

  1. Given requests with parameters, which parameters are worth attacking and for which vulnerability class? This is the analyze mode -- it takes existing traffic and identifies high-value targets.

  2. Given a bare URL with no parameters, what parameters should I try adding? This is the discover mode -- it classifies the endpoint type and suggests parameters to fuzz, prioritized by relevance.

The 21 Vulnerability Categories

  • idor -- IDOR/BOLA: user_id, account_id, order_id, resource, numeric IDs
  • sqli -- SQL injection: query, search, filter, sort, order_by
  • ssrf -- SSRF: url, uri, endpoint, callback, webhook, fetch
  • xss -- XSS: message, comment, content, html, text, markup
  • cmdi -- Command injection: cmd, exec, command, shell, run
  • lfi -- Path traversal/LFI: file, path, include, template, page
  • ssti -- Template injection: template, render, view, layout
  • auth -- Authentication: token, session, password, key, secret, apikey
  • redir -- Open redirect: redirect, return_url, next, goto, continue
  • mass -- Mass assignment: role, isAdmin, permission, privilege, admin
  • xxe -- XXE: XML bodies with DOCTYPE, ENTITY
  • debug -- Debug endpoints: debug, trace, verbose, test, dev
  • graphql -- GraphQL: query, mutation, variables, operationName
  • gateway -- Gateway bypass: X-Forwarded-For, X-Real-IP, X-Original-URL
  • edge -- Edge/CDN: cf-ray, x-vercel-id, fastly-*
  • cloud -- Cloud metadata: role, iam, bucket, region
  • prototype -- Prototype pollution: __proto__, constructor, prototype
  • ai_llm -- AI/LLM: prompt, model, temperature, system, instruction
  • workflow -- Workflow: step, stage, transition, action, state
  • saas -- SaaS abuse: stripe, payment, amount, price

Analyzing Captured Traffic

Pass URLs or Hugin flows to the analyzer. Each parameter in each request is matched against all signals for the appropriate context (query string, body, header, cookie, path).

For each match the output includes:

  • The parameter name
  • Its current value (if present)
  • The matched category and signal name
  • The context it appeared in (query, body, header, cookie, path)
  • The confidence level (High, Medium, Low)
  • Whether the value itself carries risk (e.g. a numeric ID, a URL value, true for a boolean admin flag)
  • Any detected contextual pair
  • The detected framework (WordPress, Spring, Keycloak, etc.)

Confidence Adjustment

Signal confidence starts at the level defined in the signal database but is adjusted upward based on the actual parameter value:

  • user_id=42 -- Short numeric value for an IDOR signal upgrades confidence to High.
  • isAdmin=true -- Boolean admin-true for a mass-assignment signal upgrades to High.
  • redirect=http://evil.com -- URL value for an SSRF/redirect signal upgrades to High.
  • file=../../etc/passwd -- Path traversal pattern in a value upgrades to High.
  • template={{7*7}} -- Template syntax in a value for SSTI upgrades to High.

Contextual Pairs

Nerve detects 20 high-risk parameter combinations that individually might be medium risk but together indicate a specific attack surface:

  • url + webhook -- SSRF data exfiltration
  • token + redirect -- OAuth token theft
  • model + prompt -- LLM prompt injection
  • role + user_id -- Privilege escalation
  • grant_type + client_id -- OAuth flow manipulation
  • namespace + pod -- Kubernetes access
  • bucket + key -- S3 object manipulation
  • __proto__ + exec -- Prototype pollution RCE chain
  • cache_key + host -- Cache poisoning
  • x_forwarded_host + cache -- Web cache poisoning
  • password + email -- Credential attack surface
  • query + variables -- GraphQL injection
  • function + payload -- Serverless RCE
  • success_url + stripe -- Post-payment redirect hijack
  • trace_id + service -- Distributed tracing abuse
  • service_id + upstream -- Service mesh lateral movement
  • x_forwarded + internal -- WAF/ACL bypass
  • x_original_url + admin -- Path-based ACL bypass
  • constructor + prototype -- Full prototype pollution chain
  • stripe + amount -- Payment amount manipulation

When a pair is detected, each finding from those parameters carries the pair label.

CamelCase Normalization

Parameters like userId are automatically normalized to user_id before matching. The original parameter name is preserved in the output. This prevents misses on APIs that use camelCase naming.

Parameter Discovery for Bare URLs

When you have a list of endpoints with no existing parameters, Nerve can suggest what to add.

The endpoint classifier detects the type (api, auth, search, upload, admin, redirect, export, webhook, user, payment, integration, dev_staging, swagger) from URL structure. Technology indicators (Next.js, GraphQL, WordPress, Java, PHP, .NET, Node.js, Keycloak, cloud SaaS) are detected from path and hostname patterns.

Each endpoint type is mapped to high-priority and medium-priority vulnerability categories. Parameters are extracted from the signal database for those categories and returned in priority order, tagged with the context where they should be tested (query, body, header, cookie).

Exclusion Rules

Nerve filters out noise automatically:

  • External social/analytics domains (Twitter, Google Analytics, Facebook) are excluded entirely.
  • Pagination parameters with small numeric values (page=2, limit=10) are excluded for LFI signals.
  • Drupal CSS aggregation parameters (css?include=...&delta=0) are excluded for LFI.
  • Static asset versioning (app.js?v=1.2.3) is excluded.
  • Any of the above exclusions are overridden if the actual value carries a risk indicator (e.g. ?include=../../etc/passwd still fires even on a Drupal CSS URL).

Analyzing Proxy Flows Directly

Nerve accepts flows from the proxy store directly. This parses the full request including method, path segments, query string, body (JSON and form-urlencoded), headers, and cookies. JSON bodies are flattened -- {"user": {"id": 42}} produces a body parameter user.id = 42 and also checks the leaf key id independently.

Output Sorting

Results are sorted by confidence descending (High before Medium before Low), then by category, then by parameter name. High-confidence findings with risk-bearing values appear at the top.

MCP Tool: paramhunter

The Nerve engine is exposed as the paramhunter MCP tool.

Actions:

  • analyze -- Analyze URLs for parameter signals. Pass urls (array of URLs with query parameters).
  • analyze_flows -- Analyze captured proxy flows. Pass flow_ids (array of UUIDs) or host (string) with optional limit.
  • discover -- Suggest parameters for bare URLs. Pass urls (array of endpoints).
  • categories -- List all 21 vulnerability categories with signal counts.
  • info -- Get detailed info for a specific category including all signals. Pass category (short name).
  • stats -- Total signal counts across all categories.

Integration with Flow Details

Nerve findings are automatically included when you retrieve flow details via the flow_detail MCP tool. The nerve_findings field on each flow shows which parameters matched which vulnerability categories, without requiring a separate tool call.

Aggregated Nerve statistics for the current project are available via the intelligence MCP tool with the nerve_findings and nerve_stats actions.

Crawler

The crawler discovers URLs, forms, and API endpoints on a target by following links and analyzing page content. Every request it makes is captured as an HttpFlow and stored in the current project, making the results available for the scanner, Nerve, and other tools. It does not require you to browse the application manually.

Crawl Strategies

Two traversal strategies are available:

BFS (breadth-first) -- explores all links at the current depth before going deeper. Produces more uniform coverage and terminates earlier when the depth limit is reached. This is the default.

DFS (depth-first) -- follows links as deep as they go before backtracking. Useful for reaching deeply nested pages that BFS might not reach within the page limit.

Both strategies use the same URL frontier for deduplication.

Scope Control

The scope controls which URLs the crawler follows. Scope evaluation has this priority order:

  1. Exclude patterns -- regex matched against the full URL. If any exclude pattern matches, the URL is out of scope regardless of other settings.
  2. Include patterns -- regex matched against the full URL. If any include pattern matches, the URL is in scope.
  3. Seed host matching -- the crawl stays on the same host as the seed URL(s). Subdomains can be included or excluded independently.

By default, include_subdomains is true, so a seed of example.com also follows api.example.com and static.example.com. Set it to false for strict host-only scope.

Configuration

{
  "max_depth": 3,
  "max_pages": 1000,
  "concurrency": 10,
  "delay_ms": 100,
  "per_host_delay_ms": 1000,
  "timeout_secs": 30,
  "respect_robots": true,
  "parse_sitemap": true,
  "submit_forms": false,
  "js_analysis": true,
  "enable_passive": false,
  "capture_redirects": true,
  "probe_methods": false,
  "strategy": "bfs"
}
  • max_depth -- Maximum link depth from seed URLs. Default is 3.
  • max_pages -- Maximum total pages to visit. The crawl stops when this is reached.
  • concurrency -- Number of parallel worker tasks. The per-host rate limiter (per_host_delay_ms) operates independently from the global delay_ms.
  • respect_robots -- Fetch and honor robots.txt for the target host before crawling.
  • parse_sitemap -- Fetch and enqueue sitemap.xml at crawl start to seed the frontier.
  • submit_forms -- Fill and submit detected forms with synthetic values (see Form Detection below).
  • js_analysis -- Parse JavaScript for embedded URLs and API endpoints (see JavaScript Analysis below).
  • enable_passive -- Fetch historical URLs from Wayback Machine, CommonCrawl, and AlienVault OTX before crawling.
  • capture_redirects -- Record each redirect hop as a separate flow. Useful for spotting open redirects.
  • probe_methods -- Issue HEAD and OPTIONS requests per URL in addition to GET. Detects allowed-method misconfigurations.
  • custom_headers -- Headers added to every request (e.g. Authorization, session cookies).
  • proxy -- Route all crawler traffic through an HTTP proxy (e.g. http://127.0.0.1:8080).

JavaScript Analysis

When js_analysis is enabled, the crawler parses all JavaScript encountered -- both inline <script> blocks and external script files. It extracts:

  • Relative and absolute URLs referenced in JS code
  • API endpoint paths constructed in JS (string literals, template literals)
  • External script source URLs

Discovered URLs are added to the frontier and crawled if they are in scope. This is a static analysis pass, not dynamic execution -- it finds strings that look like URLs without running the code.

The crawler also extracts inline event handlers from HTML attributes (onclick, onsubmit, onchange, etc.) and logs them for manual review.

Form Detection and Submission

The crawler parses all HTML forms it encounters, including:

  • Form action URL and method (GET/POST)
  • Input field names, types, and default values
  • Hidden fields

When submit_forms is enabled, the form submitter fills detected forms with synthetic values appropriate to the field type (text fields get test, email fields get test@test.com, number fields get 1, etc.) and submits them. The resulting request/response is captured as a flow.

Form submission respects the crawl scope -- forms that would submit to out-of-scope URLs are not submitted.

Headless Browser Mode

When the headless feature is compiled and headless_config is set, the crawler spawns a headless Chromium browser for pages that require JavaScript to render:

  • Executes JavaScript and waits for network idle before extracting links
  • Captures XHR and fetch requests made during page load as flows
  • Detects SPA routing and captures client-side navigation

Headless mode is slower and more resource-intensive than the default HTTP mode. Use it selectively for SPAs where static analysis misses significant application surface.

Passive URL Sources

When enable_passive is true, the crawler fetches historical URLs from:

  • Wayback Machine (web.archive.org)
  • CommonCrawl
  • AlienVault OTX

These URLs are added to the frontier before crawling begins. This can surface paths that are no longer linked from the live application but still exist on the server.

Trap Detection

The crawler includes a trap detector that prevents infinite loops caused by:

  • Calendars with infinite next/previous month links
  • Pagination that generates unbounded page numbers
  • Session tokens embedded in URLs that create unique URLs per visit
  • Dynamic content that generates unique paths on every request

When a URL pattern is identified as a trap, the crawler skips it and logs the detection.

robots.txt

When respect_robots is enabled, the crawler fetches robots.txt from the seed host's root and applies all Disallow and Allow rules for the configured user agent. Disallowed paths are not added to the frontier and are not visited.

To crawl disallowed paths (for authorized penetration testing), set respect_robots: false.

User Agent Rotation

The crawler supports a pool of user agent strings that rotate across requests. By default it uses a fixed user agent string. Configure a pool of agents to rotate through on each request, which can help bypass simple bot-detection rules.

Exported Flows

Every URL the crawler visits is stored as an HttpFlow in the project. The flow includes the request (method, URL, headers, body), the response (status, headers, body up to 512 KB), timing data, and metadata tags identifying the source as the crawler.

These flows appear in the proxy logger immediately and are available for scanning, Nerve analysis, and export.

MCP Tool: crawler

Actions:

  • start -- Begin a crawl with seed URLs and configuration.
  • stop -- Stop the current crawl.
  • pause / resume -- Pause and resume a crawl in progress.
  • status -- Get crawl progress (pages visited, queue depth, URLs found).
  • urls -- Get the list of discovered URLs.
  • export -- Export discovered URLs in json, csv, or txt format.

There is also a standalone vurl_crawler MCP tool that uses the Vurl HTTP engine and works without the Hugin proxy running. It supports multiple routing modes (direct, Mullvad, Hugin proxy, custom proxy) and has its own session management with start, stop, pause, resume, status, urls, export, list, and delete actions.

RatRace -- Race Condition Testing

RatRace tests endpoints for race conditions by sending multiple concurrent requests with precisely synchronized timing. The goal is to compress the request window so that concurrent state checks at the server overlap, bypassing rate limits, double-spend protections, and other concurrency guards.

Sync Engines

Five engines control how requests are synchronized before release.

Barrier -- All worker tasks build their complete request and wait at a tokio barrier. When all workers have arrived, the barrier releases them simultaneously. Works well for targets over local or low-latency links. This is the default engine for most tests.

LastByte -- Holds back the final bytes of each request until all connections are ready, then releases the last bytes at once. All workers establish a TCP connection and write the request body up to hold_percentage of the payload, then wait. On release, the held bytes are written simultaneously. Three sync methods:

  • TcpNagle -- disables Nagle's algorithm so each byte is sent immediately. Effective over low-RTT links.
  • H2Multiplex -- multiplexes all requests over a single HTTP/2 connection. The server receives all DATA frames in one TCP segment.
  • SinglePacket -- forces all DATA frames into a single TCP packet using socket-level control. Tightest synchronization available.

SinglePacket -- Opens one HTTP/2 connection and sends all requests as concurrent streams. Each stream is a separate concurrent request from the server's perspective but all arrive in the same TCP segment.

GraphqlBatch -- For GraphQL endpoints, packs multiple query operations into a single batched request body. The server processes them concurrently if batching is enabled.

Auto -- Probes the target for H2 support and selects SinglePacket if available, otherwise falls back to LastByte with TcpNagle.

Race Enhancements

Enhancements modify the base configuration to probe for different race condition variants:

  • Jitter -- Adds random delay (0 to jitter_max_ms) to each worker before release. Tests endpoints that detect uniform timing.
  • Warmup -- Issues N requests before the actual race to warm connection pools and JIT paths. Reduces cold-start variance.
  • Token rotate -- Uses a different session token per request. Detects per-token rate limits that fail to properly isolate state.
  • Method mix -- Varies the HTTP method (GET/POST/HEAD) across concurrent requests. Triggers server-side dispatch divergence.
  • Header race -- Adds X-Race-Request: 1 and similar headers. Some caching layers or middleware handle these differently.
  • Protocol hop -- Sends some requests over HTTP/1.1 and others over HTTP/2. Useful when the load balancer routes them to different backend instances.
  • Lag induction -- Deliberately delays one request by N milliseconds within the race window. Probes TOCTOU windows of specific widths.
  • Lock timeout -- Tests with configurable lock wait thresholds to find timeout-based race windows.
  • Fuzz -- Mutates parameter values across concurrent requests to test input-dependent state handling.

Endpoint Discovery

RatRace automatically classifies endpoints into 17 race-prone categories:

  • payment -- Payment processing, checkout, charge, invoice
  • auth -- Login, signin, 2FA/MFA, OTP verification
  • referral -- Promo codes, coupons, vouchers, rewards, claims
  • inventory -- Stock, cart, reservations, bookings, allocations
  • file -- Uploads, imports, attachments
  • webhook -- Webhook callbacks, notifications
  • social -- Votes, likes, follows, favorites, reviews
  • api -- Transfers, withdrawals, deposits, balance mutations
  • ghost_write -- Comments, posts, messages, replies
  • limit_reset -- Rate limit resets, quota updates
  • state_transition -- Approve/reject, enable/disable, activate/cancel
  • subscription_downgrade -- Plan changes, tier upgrades/downgrades
  • mfa_bypass -- MFA verification endpoints
  • double_dip_webhook -- Payment webhooks (Stripe, PayPal IPN)
  • password_reset_race -- Password reset, forgot-password flows
  • cdn_cache -- Static assets, cache purge endpoints
  • ssrf_file_swap -- URL fetch, proxy, preview, screenshot endpoints

Each category has associated HTTP methods and a base confidence score. The discover action scans a list of URLs and returns race-prone endpoints ranked by confidence.

Static Code Scanner

RatRace includes a static code scanner that finds race condition patterns in source code. It supports 6 languages:

  • JavaScript/TypeScript -- Non-atomic read-modify-write, missing locks, async race patterns
  • Python -- Thread-unsafe globals, missing GIL-aware locks, async race conditions
  • Go -- Goroutine data races, missing mutex, channel misuse
  • Ruby -- Thread-unsafe class variables, missing synchronize blocks
  • PHP -- File-based locking issues, session race conditions
  • Java/Kotlin/Scala -- Missing synchronized blocks, non-atomic compound operations, ConcurrentModificationException patterns

Race Signals

Every race result is classified into one of seven signals:

  • CleanCatch -- Multiple requests produced divergent responses with clear indication of a logic flaw (e.g., two 200 responses on a one-time-use action).
  • DirtyCatch -- Divergent responses observed but with noise. Likely real but needs confirmation.
  • SilentSuccess -- All requests succeeded but no observable divergence.
  • LogicalRace -- Divergent response codes or bodies that indicate a logic conflict (e.g., one 200 and one 409).
  • FalsePositive -- Divergence explained by normal server behavior (CDN variance, load balancer routing).
  • RateLimited -- The server detected the burst and throttled or blocked requests.
  • NoSignal -- All requests returned identical responses.

Detection

RatRace computes a ResponseFingerprint for each response: status code, body length, structural hash of JSON bodies, key header values, and latency. Timing statistics (min, max, mean, median, stddev, p95, p99) are recorded per window.

Additional detection includes:

  • Response divergence -- Different body hashes within a race window
  • Status code divergence -- Mixed status codes (e.g., 200 + 409 + 429)
  • Body length divergence -- Significant body size differences
  • Database signals -- Race-related error patterns (deadlock, duplicate key, serialization failure) in response bodies
  • State verification -- Before/after state comparison to detect double-spend or count violations

Protocol-Specific Tests

  • GraphQL Subscription Race -- Tests concurrent subscription establishment for duplicate event delivery.
  • OIDC Logout Race -- Tests concurrent logout + session-use to detect post-logout session persistence.
  • WebSocket Race -- Tests concurrent WebSocket upgrade requests for connection state races.
  • Cache Race -- Tests concurrent requests to detect cache poisoning windows during miss-to-hit transitions.

Distributed Testing

  • Microservice mode -- Sends concurrent requests to multiple different endpoints simultaneously. Detects cross-service races where operations on different microservices share backend state.
  • Orchestrate mode -- Coordinates race tests across multiple distributed agents for geographically dispersed testing.

Reporting

RatRace generates reports in three formats:

  • json -- Machine-readable session data with all timing statistics and evidence
  • csv -- Tabular results for spreadsheet analysis
  • html -- Visual report with signal classification and timing charts

MCP Tool: ratrace

Core actions:

  • test -- Full race test with complete configuration
  • detect -- Auto-detection mode (probes for race susceptibility)
  • quick -- Quick test with minimal configuration (URL, method, body, request count)
  • limit -- Rate limit bypass test
  • batch -- YAML batch configuration for multiple tests
  • sessions -- List all race test sessions
  • session -- Get a specific session by ID
  • cancel -- Cancel an in-progress session
  • result -- Get detailed results for a session

Discovery:

  • discover -- Find race-prone endpoints from a URL list
  • param_hunt -- Hunt for parameters within a race category
  • endpoints -- List all known race endpoint patterns
  • patterns -- List all 17 endpoint classification patterns

Static scanning:

  • scan -- Scan source code for race condition patterns
  • scan_findings -- Get scan findings

Protocol-specific:

  • ws -- WebSocket race test
  • microservice -- Cross-service race test
  • cache_race -- Cache poisoning race test
  • state_fuzz -- State transition fuzzing
  • orchestrate -- Multi-node distributed orchestration
  • graphql_subscription -- GraphQL subscription race test
  • oidc_logout -- OIDC logout race test

Engine configuration:

  • engine_config -- Configure engine parameters
  • engine_timing -- Get timing analysis for a session
  • engine_graphql -- Configure GraphQL batch engine

Enhancements:

  • enhance_fuzz -- Configure parameter fuzzing
  • enhance_lock -- Configure lock timeout testing
  • enhance_protocol -- Configure protocol hopping
  • enhance_lag -- Configure lag induction

Detection:

  • detect_db -- Detect database race signals in responses
  • detect_node -- Detect node divergence across distributed tests
  • detect_thresholds -- Configure detection thresholds

Advanced:

  • blind -- OOB (blind) race testing
  • multisession -- IDOR-style multi-session races
  • report / report_custom -- Generate reports

Oastify -- Out-of-Band Detection

Oastify is Hugin's built-in OOB (out-of-band) callback server. It listens for DNS, HTTP, HTTPS, SMTP, LDAP, FTP, and SMB interactions triggered by payloads injected during a scan. When a payload causes a server to make an outbound connection, Oastify receives and records that interaction, confirming blind vulnerabilities that produce no visible difference in the HTTP response.

Why OOB Matters

Many vulnerability classes -- blind SSRF, blind XXE, blind SQL injection with DNS exfiltration, LDAP injection, Java deserialization -- cannot be detected by analyzing the HTTP response alone. The vulnerable server makes an outbound connection. Without a listener to receive that connection, the finding is unconfirmable. Oastify closes this gap by providing an instrumented listener on a domain you control.

Protocol Listeners

Oastify starts seven listeners when launched:

  • DNS (port 53) -- Receives A/AAAA/TXT queries. The most universally reachable protocol -- DNS egress is rarely blocked.
  • HTTP (port 80) -- Receives HTTP GET/POST requests. Useful for SSRF and webhook redirect payloads.
  • HTTPS (port 443) -- Same as HTTP with TLS. Required when the target application enforces HTTPS-only URLs.
  • SMTP (port 25) -- Receives email delivery attempts. Useful for email header injection and server-side mail triggers.
  • LDAP (port 389) -- Receives LDAP bind and search requests. The primary OOB vector for Log4Shell-class JNDI payloads.
  • FTP (port 21) -- Receives FTP connection attempts. Some legacy XXE and SSRF payloads use FTP URIs.
  • SMB (port 445) -- Receives UNC path resolution attempts. Windows-side SSRF and XXE payloads that reference \\server\share paths.

Each listener records the source IP, source port, protocol, timestamp, and protocol-specific detail (DNS query name, HTTP path, LDAP DN, etc.).

Payload Generation

The PayloadGenerator produces correlation-tagged payloads for any of the seven protocols. Each payload contains a short correlation ID embedded in a subdomain or path:

DNS:    <corr_id>.<your-domain>
HTTP:   http://<corr_id>.<your-domain>/
HTTPS:  https://<corr_id>.<your-domain>/
SMTP:   attacker@<corr_id>.<your-domain>
LDAP:   ldap://<corr_id>.<your-domain>/dc=<corr_id>
FTP:    ftp://<corr_id>.<your-domain>/
SMB:    \\<corr_id>.<your-domain>\share

The correlation ID is configurable: alphanumeric (default), hex, or base64. Length defaults to 8 characters.

generate_all returns payloads for all seven protocols in a single call. The scanner uses this when injecting into parameters that support multiple URI schemes.

Correlation Flow

Every payload embeds a unique correlation ID. When Oastify receives an interaction, it extracts that ID from the DNS query name, HTTP Host header, or LDAP DN and matches it against the active payload set. The scanner marks the corresponding finding as confirmed when a match arrives.

The correlation lookup is available to the scanner (built-in checks) and to Synaps WASM modules via the Context trait:

let payload = ctx.oastify_dns(Some("my-check"))?;
// Inject payload.payload into the target request
// ...
if ctx.oastify_was_triggered(&payload.correlation_id) {
    return Ok(CheckResult::vulnerable(Confidence::Confirmed)
        .with_message("OOB DNS interaction received"));
}

Configuration

Oastify requires a domain you control with a wildcard DNS record pointing to your Oastify server's IP (*.your-domain.com -> server-ip).

Standalone Server Mode

hugin-oastify-server is a separate binary that runs just the Oastify listeners without the full proxy. Deploy it on a VPS or cloud instance reachable from your targets:

hugin-oastify-server --domain oob.example.com --bind 0.0.0.0

The standalone server exposes the same HTTP API as the embedded Oastify. Point Hugin's callback_domain setting at your VPS domain and it will poll the server for interactions via its API. This lets the proxy run locally while the callback endpoint is publicly reachable.

Integration with the Active Scanner

When callback_domain is set in ScanConfig, the built-in checks that support OOB (SSRF, XXE, LDAP injection, JWT attacks, deserialization, stored XSS) automatically include Oastify payloads. The scanner marks those findings as triggered immediately in the finding list. To confirm them, poll Oastify for the correlation ID embedded in the payload.

Checks without a callback_domain fall back to error-based detection only. OOB confirmation upgrades finding confidence to Confirmed.

Interactions

Each received interaction is stored with:

  • id -- Unique interaction UUID
  • correlation_id -- Extracted from the payload
  • protocol -- DNS, HTTP, HTTPS, SMTP, LDAP, FTP, or SMB
  • source_ip and source_port -- Where the callback originated
  • timestamp -- When Oastify received it
  • details -- Protocol-specific data (DNS query type and name, HTTP method and path, LDAP operation and DN, etc.)

All interactions are queryable by correlation ID or by time range.

MCP Tool: oastify

Actions:

  • start -- Start the Oastify server with domain and external_ip.
  • stop -- Stop the server.
  • status -- Get server status (running/stopped, listeners active).
  • domain -- Get the configured callback domain.
  • stats -- Interaction statistics (count by protocol, recent activity).
  • generate_payload -- Generate a single payload for a specific protocol (dns, http, https, smtp, ldap, ftp, smb).
  • batch_payloads -- Generate payloads for multiple protocols at once.
  • all_payloads -- Generate payloads for all seven protocols.
  • list_payloads -- List all generated payloads.
  • get_payload -- Get a specific payload by ID.
  • interactions -- List received interactions, optionally filtered by correlation ID or protocol.
  • interaction -- Get a specific interaction by ID.
  • delete_interaction -- Delete a specific interaction.
  • acknowledge -- Mark an interaction as acknowledged (confirmed by the operator).
  • acknowledge_bulk -- Bulk-acknowledge interactions.

Lua Extensions

Lua extensions are scripts that run inside the Hugin proxy and react to traffic in real time. They are the only mechanism in Hugin that can modify requests and responses in flight -- changing a URL, injecting a header, rewriting a body, or dropping a request entirely before it reaches the server.

Extensions require a Pro license.

Extension Structure

Each extension lives in its own directory under ~/.config/hugin/extensions/:

~/.config/hugin/extensions/
  my-extension/
    extension.json    # Manifest (required)
    main.lua          # Entry point (required)
    lib/              # Optional helper modules

Manifest (extension.json)

{
  "id": "my-extension",
  "name": "My Extension",
  "version": "1.0.0",
  "author": "Your Name",
  "description": "What this extension does",
  "entry_point": "main.lua",
  "hooks": ["OnRequest", "OnResponse", "PassiveCheck"],
  "permissions": ["ReadFlows", "ModifyFlows"]
}

The manifest declares the extension's identity, which hooks it subscribes to, and what permissions it requires. Hugin auto-discovers manifests by scanning the extensions directory.

Hooks

Extensions register interest in hooks via the manifest. Hugin calls the corresponding Lua function when the event fires. Six hook types are available:

OnRequest

Called before each proxied request is forwarded to the target. Can modify or drop requests. Lua function: on_request.

function on_request(ctx)
    -- ctx.flow_id    (string) Unique flow identifier
    -- ctx.method     (string) HTTP method
    -- ctx.url        (string) Full URL
    -- ctx.headers    (table)  Key-value header pairs
    -- ctx.body       (string) Request body or nil

    -- Modify headers
    ctx.headers["X-Custom-Header"] = "injected"

    -- Return action:
    -- "continue"  - forward (with any modifications applied to ctx)
    -- "drop"      - drop the request entirely
    -- or return a table with modified fields:
    return {
        headers = ctx.headers,
        url = ctx.url,
        method = ctx.method,
        body = ctx.body
    }
end

OnResponse

Called before each response is returned to the client. Can modify status, headers, body, or drop the response.

Lua function: on_response.

function on_response(ctx)
    -- ctx.flow_id    (string) Unique flow identifier
    -- ctx.status     (number) HTTP status code
    -- ctx.headers    (table)  Response headers
    -- ctx.body       (string) Response body or nil

    ctx.headers["X-Inspected-By"] = "hugin"

    return {
        headers = ctx.headers,
        status = ctx.status,
        body = ctx.body
    }
end

OnFlowCapture

Called after a complete request-response pair has been recorded. Read-only -- cannot modify the flow.

Lua function: on_flow_capture.

function on_flow_capture(ctx)
    if hugin.string_contains(ctx.url, "/api/admin") then
        hugin.log("warn", "Admin API call detected: " .. ctx.url)
    end
end

OnScanResult

Called when the active scanner produces a finding. Can enrich or filter findings.

Lua function: on_scan_result.

function on_scan_result(finding)
    -- finding.issue_type, finding.severity, finding.title, finding.description
    hugin.log("info", "Finding: " .. finding.title)
end

PassiveCheck

Runs passive analysis on every captured flow. Return a table of findings.

Lua function: passive_check.

function passive_check(request, response)
    local findings = {}

    if response.headers["x-frame-options"] == nil then
        table.insert(findings, {
            issue_type = "missing-header",
            severity = "low",
            confidence = "certain",
            title = "Missing X-Frame-Options header",
            description = "The response does not include X-Frame-Options."
        })
    end

    return findings
end

ActiveCheck

Runs active checks that can make outbound HTTP requests. Return a table of findings.

Lua function: active_check.

function active_check(request, response)
    local result = hugin.http_get(request.url .. "?test=1")
    if result.status == 500 then
        return {{
            issue_type = "error-based",
            severity = "medium",
            confidence = "tentative",
            title = "Server error on parameter injection",
            description = "Adding ?test=1 triggered a 500 response."
        }}
    end
    return {}
end

Finding Fields

Findings returned by PassiveCheck and ActiveCheck must include:

  • issue_type (string, required) -- Category identifier (e.g. "xss", "sqli", "custom")
  • severity (string, required) -- One of: critical, high, medium, low, info
  • confidence (string, required) -- One of: certain, firm, tentative
  • title (string, required) -- Short summary
  • description (string, required) -- Detailed explanation
  • evidence (string, optional) -- Supporting evidence
  • remediation (string, optional) -- Recommended fix

API Reference

Basic API (always available)

These functions are available to all extensions regardless of permissions:

Logging:

  • hugin.log(level, message) -- Log a message. Levels: error, warn, info, debug, trace

Encoding/Decoding:

  • hugin.base64_encode(data) -- Base64 encode a string
  • hugin.base64_decode(data) -- Base64 decode a string
  • hugin.url_encode(data) -- URL-encode a string
  • hugin.url_decode(data) -- URL-decode a string
  • hugin.json_encode(table) -- Serialize a Lua table to JSON string
  • hugin.json_decode(string) -- Parse JSON string into a Lua table

Hashing:

  • hugin.hash_md5(data) -- MD5 hash, returns hex string
  • hugin.hash_sha256(data) -- SHA-256 hash, returns hex string

String Utilities:

  • hugin.regex_match(pattern, text) -- Regex match with captures. Returns a table of captured groups or nil if no match.
  • hugin.regex_find_all(pattern, text) -- Find all regex matches. Returns a table of tables (one per match).
  • hugin.string_contains(haystack, needle) -- Returns true if haystack contains needle
  • hugin.string_starts_with(s, prefix) -- Returns true if s starts with prefix
  • hugin.string_ends_with(s, suffix) -- Returns true if s ends with suffix

Guarded API (requires permissions)

These functions require specific permissions declared in extension.json. Calls without the required permission will raise an error and be audit-logged.

FileSystem permission:

  • hugin.read_file(path) -- Read file contents as string
  • hugin.write_file(path, contents) -- Write string to file
  • hugin.file_exists(path) -- Check if a file exists (returns boolean)

NetworkAccess permission:

  • hugin.http_get(url, [headers]) -- HTTP GET request. Returns {status, body, headers}. 30-second timeout, follows up to 10 redirects.
  • hugin.http_post(url, body, [headers]) -- HTTP POST request. Returns {status, body, headers}.
  • hugin.http_request(method, url, [headers], [body]) -- Generic HTTP request for any method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS).
  • hugin.timed_http_request(method, url, [headers], [body]) -- HTTP request with precise timing. Does NOT follow redirects (for accurate timing measurement). 60-second timeout.

All HTTP functions accept self-signed certificates and return a table with status (number), body (string), and headers (table).

SystemCommands permission:

  • hugin.exec(command) -- Execute a system command. This is dangerous and should be reviewed carefully before granting.

Permissions

Permissions are declared in the manifest and enforced at runtime by the sandbox. Every guarded API call is permission-checked and audit-logged.

  • ReadFlows -- Access captured HTTP flow data (read-only)
  • ModifyFlows -- Modify HTTP requests and responses in transit (required for OnRequest/OnResponse hooks that return modifications)
  • NetworkAccess -- Make outbound HTTP requests from within the extension
  • FileSystem -- Read and write files on disk
  • SystemCommands -- Execute system commands (dangerous -- review before granting)

Sandbox

All extensions run in a sandboxed Lua 5.4 environment with the following safety limits:

  • Execution timeout: 30 seconds per invocation (configurable)
  • Memory limit: 64 MB per extension instance
  • Recursion depth: 100 levels maximum
  • Instruction check interval: Safety hook fires every 10,000 Lua instructions to check timeout and memory usage
  • Permission gating: Guarded API calls fail with a clear error if the required permission is not declared
  • Audit logging: Every filesystem access, network request, and system command is logged with the extension ID, operation, and result

The sandbox prevents:

  • Infinite loops consuming CPU indefinitely
  • Memory exhaustion from unbounded allocations
  • Unauthorized access to system resources
  • Extensions blocking the proxy pipeline

Managing Extensions

Via CLI

hugin plugin install https://github.com/user/hugin-plugin-name
hugin plugin list
hugin plugin remove my-extension

Via MCP

extensions(action: "list")
extensions(action: "load", path: "/path/to/extension")
extensions(action: "enable", id: "my-extension")
extensions(action: "disable", id: "my-extension")
extensions(action: "reload", id: "my-extension")
extensions(action: "stats")
extensions(action: "test_hook", hook: "on_request", data: {...})

Via REST API

GET  /api/extensions              List all extensions
GET  /api/extensions/{id}         Get extension details
POST /api/extensions/{id}/load    Load extension
POST /api/extensions/{id}/unload  Unload extension
POST /api/extensions/{id}/enable  Enable extension
POST /api/extensions/{id}/disable Disable extension
POST /api/extensions/{id}/reload  Reload extension code
GET  /api/extensions/stats        Extension statistics
POST /api/extensions/test-hook    Test a hook with sample data

Example: JWT Token Logger

A complete extension that logs JWT tokens found in Authorization headers:

extension.json:

{
  "id": "jwt-logger",
  "name": "JWT Token Logger",
  "version": "1.0.0",
  "author": "Example",
  "description": "Logs JWT tokens from Authorization headers",
  "entry_point": "main.lua",
  "hooks": ["OnRequest"],
  "permissions": ["ReadFlows"]
}

main.lua:

function on_request(ctx)
    local auth = ctx.headers["authorization"] or ctx.headers["Authorization"]
    if auth then
        local token = auth:match("Bearer%s+(.+)")
        if token then
            local parts = {}
            for part in token:gmatch("[^%.]+") do
                table.insert(parts, part)
            end
            if #parts >= 2 then
                -- Add padding for base64
                local padded = parts[2]
                local pad = 4 - (#padded % 4)
                if pad < 4 then
                    padded = padded .. string.rep("=", pad)
                end
                local payload = hugin.base64_decode(padded)
                if payload then
                    hugin.log("info", "JWT payload: " .. payload)
                end
            end
        end
    end
    return "continue"
end

Example: CORS Header Checker

A passive check that flags overly permissive CORS configurations:

extension.json:

{
  "id": "cors-checker",
  "name": "CORS Header Checker",
  "version": "1.0.0",
  "author": "Example",
  "description": "Flags permissive CORS configurations",
  "entry_point": "main.lua",
  "hooks": ["PassiveCheck"],
  "permissions": ["ReadFlows"]
}

main.lua:

function passive_check(request, response)
    local findings = {}
    local acao = response.headers["access-control-allow-origin"]
    local acac = response.headers["access-control-allow-credentials"]

    if acao == "*" and acac == "true" then
        table.insert(findings, {
            issue_type = "cors-misconfiguration",
            severity = "high",
            confidence = "certain",
            title = "Wildcard CORS with credentials",
            description = "Access-Control-Allow-Origin: * combined with "
                .. "Access-Control-Allow-Credentials: true. "
                .. "This is a browser-level protection bypass.",
            evidence = "ACAO: " .. tostring(acao) .. ", ACAC: " .. tostring(acac)
        })
    end

    return findings
end

MCP Integration

Hugin ships a built-in Model Context Protocol (MCP) server that exposes 126 tools to AI assistants. This is the primary interface for using Hugin with Claude Code, Claude Desktop, and any other MCP-compatible client.

The MCP server runs in-process and shares state directly with the proxy engine via Arc<AppState> -- zero HTTP overhead, zero serialization boundaries. Every tool call goes through the same service layer the GUI and REST API use.

Setup

Claude Code

claude mcp add hugin -- hugin mcp

Or add to your .mcp.json:

{
  "mcpServers": {
    "hugin": {
      "command": "hugin",
      "args": ["mcp"]
    }
  }
}

Claude Desktop

Add to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Linux: ~/.config/Claude/):

{
  "mcpServers": {
    "hugin": {
      "command": "hugin",
      "args": ["mcp"]
    }
  }
}

Standalone Mode

The MCP server can also be started alongside the proxy:

hugin start --mcp

Or as a standalone process:

hugin mcp

In standalone mode, the MCP server starts its own proxy and API internally. No separate hugin start is needed.

Architecture

The MCP server (hugin-mcp crate) uses the rmcp library and communicates over stdio (stdin/stdout). It has direct access to:

  • HuginService -- business logic layer (flows, scanner, intruder, etc.)
  • HuginStore -- SQLite persistence
  • BrowserMap -- CDP/Marionette browser automation
  • ScanExecutor -- vulnerability scanner engine
  • All vurl offensive modules (Pro license)

Responses are automatically capped at 12,000 characters to prevent context window overflow. Large bodies are truncated with size indicators by default (use include_body=true for full content).

Flow IDs accept both full UUIDs and short prefixes (minimum 4 characters), similar to git short hashes.

License Tiers

  • Community (free): 42 base tools covering proxy control, flow management, scanning, intruder, repeater, decoder, sequencer, and more.
  • Pro (paid): 49 additional vurl offensive tools for parser differentials, WAF evasion, request smuggling, AI agent exploitation, cloud SSRF, and more. Plus 35 additional advanced tools (ratrace, synaps, intelligence, etc.).

Tool Reference

All 126 MCP tools grouped by category. Each tool uses an action parameter to select the operation.


Flow Management (4 tools)

list_flows -- List captured HTTP flows with optional filters for method, host, URL, status code, and flagged state.

Parameters: method, host, url_contains, status_code, flagged, limit, offset

get_flow -- Get full details of a captured HTTP flow including request, response, headers, body, and persisted intelligence (nerve findings, client-side findings, response intel). Bodies are truncated by default -- use include_body=true for full bodies. Accepts full UUIDs or short prefixes (>= 4 chars).

Parameters: id, include_body, max_body_bytes

search_flows -- Search/list captured flows. Provide query to filter by URL text, or omit to list all flows.

Parameters: query, limit

annotate_flow -- Annotate a flow: flag, unflag, highlight, comment, or delete.

Parameters: id, action (flag, unflag, highlight, comment, delete), comment, color


Proxy Control (3 tools)

intercept -- MITM intercept control: intercept, inspect, modify, forward or drop HTTP requests and responses in real time. Also controls flow recording (history capture).

Actions: status, toggle, recording, list, get, forward, drop, forward_all, drop_all, responses, response_get, response_forward, response_drop, responses_forward_all, responses_drop_all

scope -- Proxy scope management: control which hosts/URLs are captured.

Actions: get, set_mode (CaptureAll/InScopeOnly/OutOfScopeOnly/CaptureAllTagOOS), add_pattern, remove_pattern, update, export, import, save_preset, load_preset, list_presets, delete_preset, from_sitemap

proxy_status -- Proxy infrastructure info: health check, statistics, CA certificate.

Actions: health, status, ca_cert


Request Replay (2 tools)

repeater -- HTTP request repeater: replay requests with optional modifications. Set browser_port to route through a running browser's JS fetch() for real TLS fingerprint (JA3/JA4), bypassing WAF bot detection (Akamai BMP, DataDome, Cloudflare).

Actions: send, history, queue, queue_status, raw_send, batch_raw_send, repeat, repeat_flow, batch_send, list_queue, cancel, clear_queue, proxy_status, compare

comparer -- Response comparer: compare HTTP responses for blind vulnerability detection.

Actions: compare, blind_detect, similarity


Vulnerability Scanning (9 tools)

scanner -- Active vulnerability scanner: scan flows for security issues (SQLi, XSS, SSRF, etc.).

Actions: start (provide flow_ids), status, findings, checks, cancel, pause, resume, clear, list_scans, get_scan, delete_scan, get_finding, delete_finding, update_finding, audit_items, create_finding, set_finding_status, add_finding_flow, remove_finding_flow, list_finding_flows, add_finding_tag, remove_finding_tag, list_finding_tags

scanner_audit_items -- Get scanner audit items: group vulnerability findings by check ID for a specific scan.

authz -- Authorization matrix scanner (Autorize-like): replay captured flows with different auth contexts (admin, user, no-auth), diff responses, flag access control issues.

Actions: scan, findings, export

idor -- IDOR scanner: extract parameterized IDs from captured flows, swap them with attacker's auth, compare responses.

Actions: scan, extract, findings

sqli -- SQL injection scanner: test every parameter from captured flows for SQLi using error-based, time-based blind, and boolean-based blind techniques.

Actions: scan, test_param, payloads

xss -- Reflected XSS scanner: inject probes into every parameter from captured flows, detect reflection without encoding, try context-appropriate payloads.

Actions: scan, test_param, payloads

pathtraversal -- Path traversal fuzzer: fuzz file-related parameters with 8 encoding variants (plain, URL, double-URL, UTF-8 overlong, null byte, backslash, semicolon, mixed).

Actions: scan, test_param, payloads

pipeline -- Security pipeline orchestrator: run all scanners in sequence (flow_analysis, authz, idor, sqli, pathtraversal, xss). Aggregate findings, generate reports.

Actions: run, findings, report

synaps -- Synaps WASM vulnerability scanner: run security checks using hot-swappable WASM modules.

Core actions: list, info, scan, validate, stats, tags, search. Module-specific scans: scan_ai_gateway, scan_oidc, scan_vectordb, scan_graphql_sub, scan_quic, scan_grpc_web, scan_mqtt, scan_charset_rce, scan_bare_lf, scan_rust_panic, scan_fluentbit, scan_rust_http, scan_ai_ssrf, scan_nextjs_csrf, scan_webtransport, scan_ssrf, scan_wcd, scan_cache_poison, scan_graphql_intro, scan_jwt_confusion, scan_mass_assign


Fuzzing and Discovery (5 tools)

intruder -- Intruder attack automation: fuzz parameters, brute force, enumerate. Use {} markers for injection points.

Actions: start, list, get, status, pause, resume, cancel, delete, results, grep_local, grep_data, processing, export

discover -- Content discovery: brute-force directories, files, and backup patterns. Auto-calibrates wildcard detection. Set detect_sinks=true to flag DOM XSS sinks in response bodies.

Actions: run, wildcard_check

ffuzzer -- FUZZ keyword fuzzer: replaces FUZZ (and FUZ2-FUZ9 for multi-keyword) in URL/headers/body with wordlist entries. Two modes: http (raw TCP/TLS, fast) and browser (Mullvad Browser via Marionette, bypasses TLS fingerprinting).

param_discover -- Parameter discovery: fuzz parameter names to find hidden/undocumented params. Batch testing (10 params/request) then individual verification via response diffing.

Actions: run, check

api_spec -- API specification auto-discovery: probe known spec paths (OpenAPI/Swagger, GraphQL introspection, WSDL/SOAP, Docker registry) and parse into structured routes and parameters.

Actions: discover, parse


Intelligence and Analysis (5 tools)

intelligence -- Cross-flow intelligence engine: aggregate analysis of captured HTTP traffic.

Params: params, param_search, param_stats, param_endpoint. Routes: routes, route_detail. Reflections: reflections, reflection_candidates, reflection_stats. Endpoints: endpoints, endpoint_detail, endpoint_stats. Security: rollups, rollup_summary, rollup_host. Nerve: nerve_findings, nerve_stats. Client-side: client_side, client_side_stats. Response: response_intel, response_intel_stats. Gold: gold. Backfill: analyze. Purge: purge_intel. Auth: auth_diff.

paramhunter -- Parameter signal analysis: maps HTTP parameter names/values to 21 vulnerability categories with 700+ regex signals and confidence levels.

Actions: analyze, analyze_flows, categories, info, stats

flow_analysis -- Flow security analyzer: scan captured proxy traffic for postMessage handlers and DOM sinks.

Actions: postmessage, dom_sinks, all

fingerprint -- Technology fingerprinting: passive detection of web technologies from HTTP headers and response content.

Actions: categories, signatures, security_headers, recommend, analyze_headers, profile

scan_optimizer -- AI-powered scan optimization: intelligent priority scoring and adaptive scanning.

Actions: analyze, recommend_checks, profile, stats, learn


Race Condition Testing (1 tool)

ratrace -- Race condition testing engine: test for TOCTOU, double-spend, rate limit bypass vulnerabilities.

Core actions: test, detect, quick, limit, batch, sessions, session, cancel, result, discover, param_hunt, endpoints, scan, scan_findings, ws, microservice, cache_race, state_fuzz, orchestrate, report, graphql_subscription, oidc_logout. Engine config: engine_config, engine_timing, engine_graphql. Enhancements: enhance_fuzz, enhance_lock, enhance_protocol, enhance_lag. Detection: detect_db, detect_node, detect_thresholds. Advanced: blind, multisession, patterns, report_custom.


Encoding and Decoding (2 tools)

decoder -- Decoder/encoder for security testing. 622 polyglot payloads across 66 contexts (XSS, SQLi, NoSQL, command injection, SSTI, XXE, SSRF, path traversal, and many more).

Actions: encode, decode, chain, analyze, reencode, jwt_decode, jwt_forge, polyglot, operations

smart_decode -- Smart decoder: auto-detect encoding chains (base64, URL, HTML entities, hex, JWT, unicode escapes, gzip, double-URL) and decode layer by layer.

Actions: detect, auto_decode, detect_and_decode, encodings


Site Map and Crawling (3 tools)

site_map -- Site map: explore captured HTTP traffic by host and path.

Actions: hosts, hosts_simple, host, paths, flows, search, stats, tree, export, path_detail

crawler -- Web crawler: discover pages, forms, and URLs by crawling a target site.

Actions: start, stop, pause, resume, status, urls, export

vurl_crawl -- Standalone web crawler using Vurl HTTP engine. Works without Hugin proxy running. Supports multiple routing modes (direct, mullvad, hugin, custom proxy).

Actions: modes, check_proxy, start, stop, pause, resume, status, urls, export, list, delete


Session and Authentication (4 tools)

session -- Session and authentication management: track tokens, create login macros, auto-refresh sessions.

Actions: tokens, status, list_macros, create_macro, get_macro, delete_macro, execute_macro, refresh

hugin_cookie_jar -- Cookie jar management: view, edit, delete, filter, import/export cookies from proxy sessions.

Actions: list, get, set, delete, clear, domains, export, import, from_flows, expired, purge_expired

hugin_macros -- Session macros: record, edit, and replay multi-step request sequences for session maintenance and authentication.

Macro actions: list_macros, get_macro, create_macro, update_macro, delete_macro, run_macro, test_macro. Rule actions: list_rules, create_rule, update_rule, delete_rule, enable_rule, disable_rule

settings -- Proxy and HTTP/2 settings: configure upstream proxy, per-host rules, presets, HTTP/2 options.

Actions: get_proxy, set_proxy, clear_proxy, list_rules, add_rule, remove_rule, replace_rules, test_proxy, preset (tor/burp/mullvad/disable), get_http2, set_http2


Browser Automation (2 tools)

browser -- Browser automation: launch Chrome (CDP) or Mullvad Browser (Marionette) through Hugin proxy, navigate to URLs, capture all traffic, and run full recon pipeline.

Actions: launch, browse, navigate, crawl, status, stop, exec_js, source, screenshot, new_tab, switch_tab, close_tab, list_tabs

screenshot -- Screenshot capture for bug bounty PoC evidence. Uses the existing browser session from BrowserMap.

Actions: capture, capture_flow, capture_ui, record_start, record_stop, list


OOB Detection (2 tools)

oastify -- Rust-native OOB server: local out-of-band interaction detection with DNS and HTTP listeners.

Actions: start, stop, status, domain, stats, generate_payload, batch_payloads, all_payloads, list_payloads, get_payload, interactions, interaction, delete_interaction, acknowledge, acknowledge_bulk

vurl_oastify -- Oastify OOB callback tracking: central hub for all tools (intruder, vsploit, scanner, manual). Connect to oastify server, register payloads with unique tracked markers, poll/sync for callbacks.

Actions: connect, disconnect, status, generate, register_batch, payloads, interactions, sync, stats, commands, generate_local


Token Analysis (1 tool)

sequencer -- Token randomness sequencer: capture tokens from repeated requests and analyze their randomness quality (FIPS statistical tests).

Actions: capture, tokens, stop, analyze, list, delete, status, compare, export


Project Management (2 tools)

project -- Project isolation: manage per-target project profiles with isolated scope, flows, and recon data.

Actions: create, list, get, update, delete, activate, deactivate, archive, scope, stats, assign_flows, export, templates, create_from_template, fingerprint, import_scope, policy_get, policy_set, policy_search. Legacy: save, load, recent

hugin_environment -- Manage named environments and variables: create environments, set/get/delete variables, activate.


Reporting and Export (3 tools)

reporting -- Generate security reports in various formats.

Actions: sarif, summary, html, markdown, csv, formats, executive_summary, templates, list_templates, save_template, delete_template, generate, issue_select

hugin_exports -- Export captured flows and project data in JSON, CSV, or HAR format.

output_store -- Searchable output storage for large tool results. Stores outputs from intruder, repeater, scanner in SQLite with FTS5 full-text search.

Actions: list, search, get, delete, delete_old, stats


Organization and Workflow (6 tools)

dashboard -- Dashboard overview: get event log, active tasks, and aggregated stats.

Actions: events, tasks, stats

events -- Event log management: view, filter, and manage system events.

Actions: list, recent, stats, clear, delete_before

hugin_organizer -- Organizer: save, categorize, annotate, and search interesting HTTP requests for triage and reporting.

Actions: list, get, save, update, delete, search, categories, tags, export, bulk_tag, bulk_delete

hugin_collections -- Manage collections: curated bundles of HTTP requests with annotations.

Actions: list, get, create, update, delete, add_flow, add_raw, remove_item, reorder, annotate_item, export, import, duplicate, share

hugin_scheduler -- Manage scheduled scan jobs: list, create, update, delete, trigger, and view run history.

hugin_workflows -- Manage event-driven workflows: create triggers and actions for automated flow processing.


Rules and Filters (3 tools)

rules -- Manage intercept rules for request/response filtering and actions. Rules can match by host, path, method, headers, body content.

Actions: list, get, create, update, delete, groups_list, groups_create, groups_delete

hugin_logger_filters -- Logger filter management: save/load filter presets for HTTP history, manage capture filter rules for conditional logging.

Preset actions: list_presets, get_preset, save_preset, delete_preset, apply_preset. Capture filter actions: list_capture_filters, create_capture_filter, update_capture_filter, delete_capture_filter, enable_capture_filter, disable_capture_filter

hugin_bambda -- Bambda: Lua filter expressions for flow tables. Write inline Lua code to filter, search, and transform captured proxy traffic.

Actions: filter, transform, test, presets, save_preset, delete_preset


DOM/Client-Side Security (4 tools)

hugin_taint -- Browser-based DOM XSS taint analysis: launch headless Chrome to trace data flow from user-controlled sources to dangerous sinks.

Actions: scan, analyze_flow, sources, sinks

hugin_cors -- CORS misconfiguration scanner: test Access-Control-Allow-Origin / Access-Control-Allow-Credentials behavior with 9 origin probes.

Actions: scan, scan_flow, techniques

hugin_upload -- File upload vulnerability scanner: test upload endpoints with 16 extension variants, 6 content-type mismatches, double extensions, null byte injection, and polyglot file generation.

Actions: scan, techniques, generate_polyglot

vurl_postmessage -- postMessage security scanner: static analysis of JS chunks for postMessage handlers, origin validation quality, and event.data flow into dangerous sinks.

Actions: analyze, patterns, scan_url


JS Analysis (4 tools)

vurl_js_sinks -- JS chunk DOM sink finder: download JavaScript chunks from a page, scan for dangerous sinks (innerHTML, eval, document.write) and track controllable data sources.

Actions: analyze, sinks, scan_url

vurl_js_endpoints -- JS endpoint extractor: extract API routes, URLs, fetch/XHR calls, GraphQL operations, and WebSocket endpoints from JavaScript.

Actions: analyze, scan_url, patterns, mine_params

vurl_endpointer -- EndPointer: endpoint behavioral profiler. Probes discovered API endpoints to build behavioral profile cards across 20 tiers.

Actions: probe, batch, methods, auth, profile

vurl_csp_nonce -- CSP nonce leak detector: detect nonce values in CSP headers, meta tags, and script attributes. Test nonce reuse across multiple requests.

Actions: detect, headers, reuse


Next.js / React (3 tools)

vurl_hydration -- Generate Next.js RSC hydration hijacking payloads. Exploits __NEXT_DATA__, RSC chunks, multipart prototype pollution.

Actions: generate, categories

vurl_nextjs_rsc -- Next.js RSC (React Server Components) analyzer: parse RSC flight data, detect component tree leaks, test nonce reuse, cache poisoning.

Actions: analyze, nonce, cache_poison, reflection

vurl_nextjs_middleware -- Next.js middleware bypass tester: test header-based, path normalization, locale prefix, and _next/data route bypasses.

Actions: test, headers, paths, locale


HTTP Smuggling (2 tools)

vurl_smuggle -- HTTP request smuggling payloads and detection.

Actions: payloads (CL.TE/TE.CL), te_variants, host, keep_alive, probe_0cl, probe_cl0, double_desync, early_gadgets, full_scan, header_casing

vurl_harvest -- SmuggleHarvester: continuous request smuggling attack daemon. Rotates through confirmed techniques, captures victim data.

Actions: start, stop, status, list, results, techniques


SSRF and Cloud (4 tools)

vurl_cloud -- Generate cloud metadata SSRF payloads for AWS, GCP, Azure, DigitalOcean, Alibaba, Oracle, Kubernetes, Docker. Includes IMDSv1/v2.

vurl_ssrf_detect -- SSRF detection engine: analyze responses for SSRF indicators and perform timing-based blind SSRF detection.

Actions: analyze, indicators, timing_baseline, timing_analyze, timing_compare, is_blocked

vurl_k8s -- Generate Kubernetes SSRF payloads (IngressNightmare, storage controller, admission webhooks).

Actions: generate, types

vurl_redirect -- Open redirect chain payloads for SSRF.

Actions: generate, params, redirectors


WAF Evasion and Fingerprinting (6 tools)

vurl_evade -- Generate WAF evasion payloads using encoding tricks, case manipulation, null bytes, unicode normalization.

vurl_waf_evasion -- WAF evasion techniques: encoding mutations, protocol quirks, Unicode tricks, chunked abuse.

Actions: evade, categories

vurl_mirage -- Browser fingerprint spoofing and WAF evasion via Mirage module. Generate coherent browser profiles (TLS JA3/JA4, HTTP/2 AKAMAI fingerprints).

Actions: bypasses, profiles, headers, oracle, techniques

vurl_sni -- TLS SNI manipulation for WAF bypass. Exploits disconnect between TLS SNI (routing) and HTTP Host header (application).

Actions: payloads, openssl, ncat, python, curl, raw, all

vurl_fingerprint -- Parser fingerprinting via probe requests. Identifies target parser behavior.

Actions: probes, all_probes, categories, signatures

vurl_charset -- Generate charset-based RCE payloads using Best-Fit/Worst-Fit encoding attacks (Orange Tsai research).

Actions: generate, command, path, curl, encodings, attack_types


URL Parsing and Mutation (3 tools)

vurl_compare -- Compare how different URL parsers interpret a URL. Detects parser differentials exploitable for SSRF bypass, open redirect, and path traversal.

vurl_hunt -- Hunt for parser differential vulnerabilities by generating URL mutations and comparing parser outputs.

vurl_mutator -- URL mutation engine for parser differential hunting. 15+ mutator strategies.

Actions: mutate, chains, crlf, nfkc, strategies


HTTP Client (4 tools)

vurl_http -- Send HTTP request with full control over method, headers, body, timeouts, redirects, and proxy. Keep max_body_size under 15000 to avoid token overflow.

vurl_http_raw -- Send raw HTTP request string for smuggling attacks, malformed requests, or protocol-level testing.

vurl_http_compare -- Compare HTTP responses from two URLs to detect behavioral differences, timing variations, and content changes.

vurl_chain -- Chain HTTP requests with variable extraction. Each step can extract values from responses (JSON path or regex) and use them in subsequent requests via {{variable}} placeholders.


Response Diffing (2 tools)

vurl_diff -- Response diffing engine for 0-day detection. Compares HTTP responses with 1-byte precision and 10ms timing resolution.

Actions: compare, quick, batch, hash, timing, config, severity_score

vurl_diffing -- Response diffing for 0-day detection: compare responses for byte-level and timing differences.

Actions: compare, timing, config


Protocol-Level Attacks (6 tools)

vurl_grpc -- Generate gRPC gateway differential attack payloads. Exploits parsing differences between gRPC gateways and backends.

vurl_grpc_matrix -- Get gRPC gateway vs backend compatibility matrix showing known differential risks.

vurl_h2 -- HTTP/2 single-packet race condition attacks. Uses frame multiplexing for microsecond-precision race conditions (James Kettle's research).

Actions: payloads, curl, turbo_intruder, templates, frame_types, config, analyze

vurl_rust_http -- Generate Rust HTTP parser differential payloads for request smuggling. Based on RUSTSEC-2020-0008, CVE-2021-32715, CVE-2025-32094.

Actions: generate, templates, matrix, endpoints, cves

vurl_hopbyhop -- Generate hop-by-hop header attack payloads for proxy bypass.

vurl_quic -- Generate HTTP/3 and QUIC attack payloads: 0-RTT replay, connection ID manipulation, QPACK table poisoning, Alt-Svc injection.

Actions: generate, curl, detect, types


Authentication Bypass (3 tools)

vurl_ip_bypass -- Generate IP spoofing headers (X-Forwarded-For, X-Real-IP, etc.) to bypass IP-based access controls.

vurl_auth_bypass -- Generate authentication bypass headers for proxy-level auth bypass attacks.

vurl_identity -- Identity protocol attacks: OIDC front-channel logout injection, session fixation, Entra ID cross-tenant sync.

Actions: oidc_logout, categories


AI/LLM Security (6 tools)

vurl_mcp_rce -- Generate AI agent exploitation payloads for MCP RCE, Langflow, CrewAI, AutoGPT, LangChain, OpenAI Assistants, Claude MCP, Gemini, Dify, Flowise.

vurl_langflow -- Langflow-specific exploitation payloads for CVE-2025-3248 and other RCE vectors.

vurl_tool_payloads -- Generate exploitation payloads for specific AI agent tool types: http_request, file_read, file_write, code_exec, shell_exec, database, browser.

vurl_llm_poison -- Generate LLM context poisoning payloads for RAG injection, system prompt extraction, jailbreaks, and tool manipulation.

Actions: generate, types

vurl_shadow_ai -- Generate shadow AI prompt injection payloads for exploiting AI agents via reflected content.

Actions: generate, json, html, categories, context, detection

vurl_ai_gateway -- AI Gateway bypass payloads for Cloudflare AI, AWS Bedrock, Azure Content Safety.

Actions: detect, bypass, encode, gateways


Payload Generation (2 tools)

vurl_payload -- Generate protocol payloads for SSRF exploitation: Redis, Memcached, SMTP, FastCGI, MySQL, PostgreSQL, LDAP, DNS, Gopher, CoAP (IoT), MQTT (IoT), Dict, GraphQL, gRPC-Web, XXE.

vurl_csd -- Client-Side Desync (CSD) attack payloads: browser-powered desync attacks.

Actions: generate, triggers


Edge Runtime and Server-Specific (4 tools)

vurl_edge -- Generate edge runtime attack payloads for Vercel Edge, Cloudflare Workers, Deno Deploy, Netlify Edge, AWS Lambda@Edge.

Actions: generate, middleware, signatures, runtimes, categories

vurl_fluentbit -- Generate Fluent Bit CVE-2025-12970 exploitation payloads. Targets 15+ billion deployments.

Actions: generate, large_payload, ssrf_endpoints, manifests, detection, categories

vurl_sharepoint -- Generate SharePoint CVE-2025-53770 exploitation payloads.

Actions: generate, cve, high_risk, categories

vurl_rust_panic -- Generate Rust panic DoS/RCE payloads targeting validation panics in Safe Rust wrappers around Unsafe C libraries. Based on CVE-2026-21895.

Actions: generate, deepsurf, templates, endpoints, categories, targets, large, cves, microservices


DNS and Network (2 tools)

vurl_rebind -- DNS rebinding timing analysis for TOCTOU exploitation.

Actions: analyze, payloads, timing

vurl_rebind_v2 -- DNS rebinding v2 with advanced async timing analysis for TOCTOU exploitation.

Actions: analyze, timing, payloads, detect, resolve


Vector Database and RAG (1 tool)

vurl_vectordb -- Vector database injection payloads for Pinecone, Milvus, Weaviate, Qdrant, Chroma.

Actions: detect, exploit, databases


Race Detection (1 tool)

vurl_race -- Race condition and parser differential detection: fire URLs at multiple endpoints and detect differences.

Actions: quick, types


Asset Management (1 tool)

assets -- Asset inventory: unified recon database for SubFlow, XMass, vmap results.

CRUD: list, get, create, update, delete, ports, events. Intelligence: stats, coverage, cluster_jarm, cluster_favicon. Ingest: ingest_subflow, ingest_xmass, ingest_vmap. Pipeline: crawl_seeds.


Mobile Security (1 tool)

mobile -- Mobile app security analysis: static analysis (APK/IPA), device management, dynamic instrumentation (Frida), proxy setup.

Actions: toolchain, devices, device_info, emulator_start, emulator_list, analyze_apk, analyze_ipa, decompile, decode, manifest, network_config, binary_info, scan_secrets, apps, app_info, install, uninstall, launch, stop, clear_data, pull_apk, frida_ps, frida_apps, frida_spawn, frida_attach, ssl_bypass, root_bypass, objection_ssl, objection_env, objection_classes, objection_methods, proxy_setup, proxy_clear, proxy_check, push_ca, check_cleartext, ios_proxy_instructions, shared_prefs, read_shared_pref, databases, dump_database, app_files, pull_storage, logcat, crash_detect, syslog, crashes, raw_shell, forward, reverse


Collaboration (1 tool)

collab -- Real-time collaboration between hunters. Share your Hugin session with a teammate (Pro license required).

Actions: share, join, status, leave, publish


Extensions and Tooling (3 tools)

extensions -- Lua extension management: load, unload, enable, disable extensions and test hooks.

Actions: list, get, load, unload, enable, disable, reload, stats, test_hook

hugin_tools_registry -- External tools registry: list registered tools, check health, execute tool commands.

hugin_files -- Manage payload file library: add, remove, list, preview, search files and manage tags.


Campaigns and Automation (1 tool)

hugin_campaigns -- Manage automation campaigns: create, configure, start/stop multi-step intruder attacks with payload sets.


Enterprise (4 tools)

rbac -- Role-Based Access Control: manage users, roles, permissions, and audit logging for multi-user environments.

Actions: list_users, get_user, create_user, update_user, delete_user, list_roles, create_role, delete_role, check_permission, audit_log, log_action

invisible_proxy -- Invisible (transparent) proxy mode: configure and manage transparent proxy interception without client-side proxy settings.

Actions: status, configure, enable, disable, generate_rules, connections, dns_config

hugin_http3 -- HTTP/3 (QUIC) proxy configuration and analysis.

Actions: status, configure, probe, alt_svc_scan, fingerprint, stats

hugin_spnego -- SPNEGO/NTLM enterprise authentication: configure credentials, detect auth challenges, generate tokens.

Actions: status, configure, list_credentials, delete_credential, detect, generate_type1, parse_challenge, generate_type3, sessions, test


MCP Resources

The MCP server also exposes resources for reading configuration and state:

  • hugin://config -- Current proxy configuration
  • hugin://scope -- Active scope patterns
  • hugin://stats -- Proxy statistics (flow count, hosts, etc.)

Usage Tips

  • Start broad: use list_flows and search_flows to understand captured traffic before diving deep.
  • Use get_flow with short ID prefixes (e.g., get_flow(id: "a3f2")) instead of copying full UUIDs.
  • For WAF-protected targets: use browser(action: "launch") first, then browser(action: "exec_js") with fetch() to make requests through the browser's real TLS fingerprint.
  • Chain tools together: vurl_js_endpoints to find endpoints, then vurl_endpointer to profile them, then intruder or sqli to test.
  • Use pipeline to run all scanners in sequence on a host with one call.
  • Track OOB callbacks with vurl_oastify -- it correlates callbacks to specific payloads automatically.

Plugin SDK

The Hugin Plugin SDK (hugin-plugin-sdk) is a Rust crate for building native plugins that integrate directly with the proxy engine. Unlike Lua extensions (which are scripts loaded at runtime), SDK plugins are compiled Rust code registered with Hugin's engine at startup.

The SDK is intentionally thin: it contains only traits and data types, no runtime machinery. Implementation details stay inside Hugin. This makes the SDK stable across minor versions.

Getting Started

Add the SDK to your plugin's Cargo.toml:

[dependencies]
hugin-plugin-sdk = "0.1"
async-trait = "0.1"

Hook Traits

The SDK provides four hook traits. Implement the ones relevant to your plugin.

RequestHook

Intercept and optionally modify HTTP requests before they are forwarded to the target.

#![allow(unused)]
fn main() {
use hugin_plugin_sdk::{RequestHook, PluginContext, HttpRequestData, HookDecision};
use async_trait::async_trait;

pub struct MyRequestPlugin;

#[async_trait]
impl RequestHook for MyRequestPlugin {
    fn name(&self) -> &'static str { "my-request-plugin" }

    // Optional: set priority (lower = earlier). Default: 100
    fn priority(&self) -> u8 { 50 }

    async fn on_request(
        &self,
        ctx: &PluginContext,
        request: &mut HttpRequestData,
    ) -> HookDecision {
        // Modify the request in place
        request.headers.push(("X-Plugin".to_string(), "active".to_string()));

        // Return decision:
        HookDecision::Allow  // Forward (with modifications)
        // HookDecision::Drop   // Drop the request
        // HookDecision::Respond(response)  // Synthetic response
    }
}
}

ResponseHook

Intercept and optionally modify HTTP responses before they reach the client.

#![allow(unused)]
fn main() {
use hugin_plugin_sdk::{ResponseHook, PluginContext, HttpRequestData, HttpResponseData, HookDecision};
use async_trait::async_trait;

pub struct MyResponsePlugin;

#[async_trait]
impl ResponseHook for MyResponsePlugin {
    fn name(&self) -> &'static str { "my-response-plugin" }

    async fn on_response(
        &self,
        ctx: &PluginContext,
        request: &HttpRequestData,
        response: &mut HttpResponseData,
    ) -> HookDecision {
        // Inspect or modify the response
        HookDecision::Allow
    }
}
}

PassiveHook

Run passive analysis on stored flows. No outbound requests. Returns findings.

#![allow(unused)]
fn main() {
use hugin_plugin_sdk::{PassiveHook, PluginContext, PluginFinding, StoredFlow, FindingSeverity};
use async_trait::async_trait;

pub struct MyPassivePlugin;

#[async_trait]
impl PassiveHook for MyPassivePlugin {
    fn name(&self) -> &'static str { "my-passive-plugin" }

    async fn analyze(&self, ctx: &PluginContext, flow: &StoredFlow) -> Vec<PluginFinding> {
        let mut findings = vec![];

        if flow.request.url.contains("admin") {
            findings.push(
                PluginFinding::new(
                    "my-passive-plugin",
                    FindingSeverity::Low,
                    "Admin endpoint detected",
                )
                .with_description("Request to admin endpoint found in captured traffic")
                .with_flow(flow.id),
            );
        }

        findings
    }
}
}

ActiveHook

Run active checks that can make outbound requests via ctx.replay(). Returns findings.

#![allow(unused)]
fn main() {
use hugin_plugin_sdk::{ActiveHook, PluginContext, PluginFinding, StoredFlow, FindingSeverity, HttpRequestData};
use async_trait::async_trait;

pub struct MyActivePlugin;

#[async_trait]
impl ActiveHook for MyActivePlugin {
    fn name(&self) -> &'static str { "my-active-plugin" }

    async fn scan(&self, ctx: &PluginContext, flow: &StoredFlow) -> Vec<PluginFinding> {
        // Replay the original request with a modification
        let mut modified = flow.request.clone();
        modified.url = format!("{}?test=1", modified.url);

        match ctx.replay(modified).await {
            Ok(response) if response.status == 500 => {
                vec![PluginFinding::new(
                    "my-active-plugin",
                    FindingSeverity::Medium,
                    "Server error on parameter injection",
                )]
            }
            _ => vec![],
        }
    }
}
}

Data Types

HttpRequestData

#![allow(unused)]
fn main() {
pub struct HttpRequestData {
    pub method: String,
    pub url: String,
    pub headers: Vec<(String, String)>,
    pub body: Option<Vec<u8>>,
}
}

HttpResponseData

#![allow(unused)]
fn main() {
pub struct HttpResponseData {
    pub status: u16,
    pub headers: Vec<(String, String)>,
    pub body: Option<Vec<u8>>,
}
}

StoredFlow

A complete request-response pair from the proxy history:

#![allow(unused)]
fn main() {
pub struct StoredFlow {
    pub id: uuid::Uuid,
    pub request: HttpRequestData,
    pub response: Option<HttpResponseData>,
    pub host: String,
    pub port: u16,
    pub is_tls: bool,
    pub timestamp: chrono::DateTime<chrono::Utc>,
}
}

HookDecision

Returned by request/response hooks:

#![allow(unused)]
fn main() {
pub enum HookDecision {
    Allow,                        // Forward (with modifications applied)
    Drop,                         // Drop entirely
    Respond(HttpResponseData),    // Synthetic response (request hooks only)
}
}

PluginFinding

Represents a security finding:

#![allow(unused)]
fn main() {
let finding = PluginFinding::new("plugin-id", FindingSeverity::High, "Title")
    .with_description("Detailed description")
    .with_flow(flow_id)  // Link to the flow that triggered it
    ;
}

Severity levels: Critical, High, Medium, Low, Info.

Confidence levels: Certain, Firm, Tentative.

PluginContext

Provided to every hook at runtime. Gives access to:

  • ctx.replay(request) -- Send an HTTP request and get the response (for active checks)
  • ctx.target_host() -- Get the current scan target hostname
  • ctx.config() -- Access per-plugin configuration (key-value pairs editable in the UI)

PluginConfig

Per-plugin configuration accessible via ctx.config():

#![allow(unused)]
fn main() {
let config = ctx.config();
let timeout = config.get_u64("timeout").unwrap_or(30);
let verbose = config.get_bool("verbose").unwrap_or(false);
let api_key = config.get_str("api_key").unwrap_or("");
}

Plugin vs Lua Extension

Choose the right extension system for your use case:

Use Lua extensions when:

  • You need to modify traffic in-flight (OnRequest/OnResponse with modifications)
  • Quick prototyping without compilation
  • Simple passive checks
  • You want hot-reload without restarting Hugin

Use the Plugin SDK when:

  • Performance-critical analysis (compiled Rust, no Lua overhead)
  • Complex logic that benefits from Rust's type system and libraries
  • Active scanning that requires concurrent HTTP requests
  • You want to distribute a binary plugin

Comparison

  • Lua extensions: Interpreted, sandboxed (30s timeout, 64MB memory), hot-reloadable, 6 hook types, permission-gated API
  • Plugin SDK: Compiled Rust, no sandbox overhead, registered at startup, 4 hook traits, full Rust ecosystem access
  • Both can produce findings that appear in Hugin's scanner results
  • Both are gated behind the Pro license

REST API

The Hugin API server exposes a REST API for automation, scripting, and integration with external tools. Every feature accessible through the UI is also accessible via REST.

Base URL and Default Port

http://127.0.0.1:8081/api/

The API port defaults to 8081 and is configurable via --api-port or the config file. An OpenAPI spec is served at /openapi.json.

Authentication

When running locally (bound to 127.0.0.1), authentication is disabled by default. When exposed on a network interface (0.0.0.0), enable authentication. See Authentication for details.

Endpoint Reference

All endpoints are prefixed with /api/ unless otherwise noted.

Infrastructure

GET  /api/health               Health check (no auth required)
GET  /api/update/check         Check for updates
GET  /api/ca.pem               Download CA certificate
GET  /api/proxy/status         Proxy status and statistics

Flows

GET  /api/flows                List flows (query params: method, host, flagged, limit, offset)
POST /api/flows                Create/import a flow
GET  /api/flows/{id}           Get flow details

Repeater

POST /api/repeater/send        Replay a request with modifications
POST /api/repeater/batch       Send batch requests
GET  /api/repeater/history     List replay history
GET  /api/repeater/queue       Queue status
POST /api/repeater/queue       Queue a request for later
GET  /api/repeater/queue/list  List queued requests
DELETE /api/repeater/queue     Clear the queue
DELETE /api/repeater/queue/{id} Cancel a queued request
POST /api/repeat               Send raw HTTP request
POST /api/flows/{id}/repeat    Replay a flow through the proxy

Intercept

GET  /api/intercept                    Intercept status
POST /api/intercept                    Toggle intercept on/off
GET  /api/intercept/pending            List pending intercepted requests
GET  /api/intercept/pending/{id}       Get a pending request
POST /api/intercept/forward/{id}       Forward a request
POST /api/intercept/drop/{id}          Drop a request
POST /api/intercept/forward-all        Forward all pending
POST /api/intercept/drop-all           Drop all pending
GET  /api/intercept/captured           List captured intercepts
POST /api/intercept/captured/clear     Clear captured intercepts

Response Intercept:

GET  /api/intercept/responses                  List pending responses
GET  /api/intercept/responses/{id}             Get a pending response
POST /api/intercept/responses/forward/{id}     Forward a response
POST /api/intercept/responses/drop/{id}        Drop a response
POST /api/intercept/responses/forward-all      Forward all responses
POST /api/intercept/responses/drop-all         Drop all responses

Rules

GET  /api/rules                List intercept rules
POST /api/rules                Create a rule
GET  /api/rules/{id}           Get rule details
PATCH /api/rules/{id}          Update a rule
DELETE /api/rules/{id}         Delete a rule
GET  /api/rules/groups         List rule groups
POST /api/rules/groups         Create a group
DELETE /api/rules/groups/{id}  Delete a group

Scope

GET  /api/scope                Get scope configuration
POST /api/scope                Update scope
POST /api/scope/mode           Set scope mode
POST /api/scope/recording      Toggle recording
POST /api/scope/pattern        Add a scope pattern
DELETE /api/scope/pattern/{p}  Remove a scope pattern

Scanner

POST /api/scanner/scan                     Start a scan
GET  /api/scanner/status                   Scan status
GET  /api/scanner/findings                 List findings
POST /api/scanner/findings                 Create a manual finding
DELETE /api/scanner/findings               Clear all findings
GET  /api/scanner/findings/{id}            Get finding details
DELETE /api/scanner/findings/{id}          Delete a finding
PATCH /api/scanner/findings/{id}           Update a finding
GET  /api/scanner/findings/{id}/flows      List flows for a finding
POST /api/scanner/findings/{id}/flows      Add flow to finding
DELETE /api/scanner/findings/{id}/flows/{flow_id}  Remove flow from finding
GET  /api/scanner/findings/{id}/tags       List finding tags
POST /api/scanner/findings/{id}/tags       Add tag to finding
DELETE /api/scanner/findings/{id}/tags/{tag}  Remove tag
GET  /api/scanner/findings/tags            List all tags across findings
POST /api/scanner/cancel                   Cancel active scan
POST /api/scanner/pause                    Pause scan
POST /api/scanner/resume                   Resume scan
GET  /api/scanner/checks                   List available checks
GET  /api/scanner/scans                    List scan history
GET  /api/scanner/scans/{id}               Get scan details
DELETE /api/scanner/scans/{id}             Delete a scan
POST /api/scanner/scans/{id}/cancel        Cancel specific scan
GET  /api/scanner/scans/{scan_id}/audit-items  Audit items for a scan

Session

GET  /api/session/tokens              List tracked tokens
GET  /api/session/status              Session status
GET  /api/session/macro               List macros
POST /api/session/macro               Create a macro
GET  /api/session/macro/{id}          Get macro details
DELETE /api/session/macro/{id}        Delete a macro
POST /api/session/macro/{id}/execute  Execute a macro
POST /api/session/refresh             Refresh all sessions

WebSocket

GET  /api/websocket/connections               List WS connections
GET  /api/websocket/connections/{id}          Get connection details
DELETE /api/websocket/connections/{id}        Close a connection
GET  /api/websocket/connections/{id}/messages Get messages
POST /api/websocket/connections/{id}/send     Send a message
GET  /api/websocket/stream/messages           SSE stream of WS messages
GET  /api/websocket/stream/connections        SSE stream of WS connections

WebSocket Intercept:

GET  /api/websocket/intercept                  Intercept status
POST /api/websocket/intercept                  Toggle WS intercept
GET  /api/websocket/intercept/pending          List pending
GET  /api/websocket/intercept/pending/{id}     Get pending message
POST /api/websocket/intercept/forward/{id}     Forward message
POST /api/websocket/intercept/drop/{id}        Drop message
POST /api/websocket/intercept/forward-all      Forward all
POST /api/websocket/intercept/drop-all         Drop all

Projects

GET  /api/projects                             List projects
POST /api/projects                             Create project
GET  /api/projects/{id}                        Get project
PUT  /api/projects/{id}                        Update project
DELETE /api/projects/{id}                      Delete project
POST /api/projects/{id}/archive                Archive/unarchive
POST /api/projects/{id}/activate               Set as active project
GET  /api/projects/{id}/stats                  Project statistics
GET  /api/projects/{id}/scope                  Get project scope
PUT  /api/projects/{id}/scope                  Update project scope
POST /api/projects/{id}/assign-flows           Assign flows to project
POST /api/projects/{id}/scope/snapshots        Create scope snapshot
GET  /api/projects/{id}/scope/snapshots        List scope snapshots
GET  /api/projects/{id}/scope/snapshots/{sid}  Get snapshot
GET  /api/projects/{id}/export                 Export project
POST /api/projects/import                      Import project
POST /api/projects/deactivate                  Deactivate project context

Legacy project API (file-based):

POST /api/project/save     Save project to file
POST /api/project/load     Load project from file
GET  /api/project/recent   List recent projects

Site Map

GET /api/hosts                          List all hosts
GET /api/sitemap/hosts                  List hosts with stats
GET /api/sitemap/hosts/{host}           Host details
GET /api/sitemap/hosts/{host}/paths     Paths for a host
GET /api/sitemap/hosts/{host}/flows     Flows for a host
GET /api/sitemap/paths/{host}/{path}    Path details
GET /api/sitemap/search                 Search URLs
GET /api/sitemap/stats                  Aggregated stats
GET /api/sitemap/tree                   Hierarchical tree
GET /api/sitemap/export                 Export site map

Sequencer

GET  /api/sequencer/captures               List capture sessions
POST /api/sequencer/capture                Start a token capture
DELETE /api/sequencer/capture/{id}         Delete session
GET  /api/sequencer/capture/{id}/status    Session status
GET  /api/sequencer/capture/{id}/tokens    Get captured tokens
POST /api/sequencer/capture/{id}/stop      Stop capture
GET  /api/sequencer/capture/{id}/export    Export session
POST /api/sequencer/analyze                Analyze tokens
POST /api/sequencer/compare                Compare token sets

Crawler

POST /api/crawler/start    Start a crawl
POST /api/crawler/stop     Stop crawl
POST /api/crawler/pause    Pause crawl
POST /api/crawler/resume   Resume crawl
GET  /api/crawler/status   Crawl status
GET  /api/crawler/urls     Discovered URLs
GET  /api/crawler/export   Export URLs

Browser

POST /api/browser/launch       Launch a browser session
POST /api/browser/sweep        Full sweep (launch + crawl)
POST /api/browser/close        Close browser
GET  /api/browser/status       Browser status
POST /api/browser/navigate     Navigate to URL
POST /api/browser/exec_js      Execute JavaScript
POST /api/browser/screenshot   Take screenshot
GET  /api/browser/list         List active browser sessions

Tunnel Mode

GET  /api/tunnel/domains        List tunnel domains
POST /api/tunnel/domains/add    Add a domain to tunnel mode
POST /api/tunnel/domains/remove Remove a domain from tunnel mode

Oastify (Native OOB Server)

POST /api/oastify-native/start              Start OOB server
POST /api/oastify-native/stop               Stop OOB server
GET  /api/oastify-native/status             Server status
GET  /api/oastify-native/domain             Get callback domain
GET  /api/oastify-native/stats              Statistics
GET  /api/oastify-native/payloads           List payloads
POST /api/oastify-native/payloads           Generate a payload
POST /api/oastify-native/payloads/batch     Generate batch payloads
POST /api/oastify-native/payloads/all       All protocol payloads
GET  /api/oastify-native/payloads/{id}      Get payload details
GET  /api/oastify-native/interactions       List interactions
GET  /api/oastify-native/interactions/{id}  Get interaction
DELETE /api/oastify-native/interactions/{id} Delete interaction
POST /api/oastify-native/interactions/{id}/acknowledge  Acknowledge
POST /api/oastify-native/interactions/acknowledge-bulk  Bulk acknowledge
GET  /api/oastify-native/interactions/correlation/{id}  By correlation ID
GET  /api/oastify-native/poll               Poll for new interactions
GET  /api/oastify-native/stream             SSE stream of interactions

Oastify (Remote Tracker)

GET  /api/oastify/status           Connection status
POST /api/oastify/connect          Connect to remote server
POST /api/oastify/disconnect       Disconnect
GET  /api/oastify/stats            Statistics
POST /api/oastify/generate         Generate tracked payload
GET  /api/oastify/payloads         List tracked payloads
GET  /api/oastify/interactions     List interactions
POST /api/oastify/sync             Sync callbacks
POST /api/oastify/register_batch   Register batch payloads

Dashboard

GET /api/dashboard/events   Event log (query: limit, since_id)
GET /api/dashboard/tasks    Active tasks
GET /api/dashboard/stats    Aggregated statistics

Events

GET    /api/events          List events (query: category, level, search, since, until)
DELETE /api/events          Clear all events
GET    /api/events/recent   Recent events from memory cache
GET    /api/events/stats    Event statistics
GET    /api/events/stream   SSE stream of events
DELETE /api/events/before   Delete events before timestamp

RatRace

POST /api/ratrace/test                   Run race condition test
POST /api/ratrace/detect                 Detect race conditions
POST /api/ratrace/quick                  Quick race test
POST /api/ratrace/limit                  Rate limit test
POST /api/ratrace/batch                  Batch race test
GET  /api/ratrace/sessions               List sessions
GET  /api/ratrace/sessions/{id}          Get session
DELETE /api/ratrace/sessions/{id}        Delete session
POST /api/ratrace/sessions/{id}/cancel   Cancel session
GET  /api/ratrace/results/{id}           Get results
POST /api/ratrace/discover               Discover endpoints
POST /api/ratrace/param-hunt             Hunt for race-prone params
GET  /api/ratrace/endpoints              List discovered endpoints
POST /api/ratrace/scan                   Full race scan
GET  /api/ratrace/scan/findings          Scan findings
POST /api/ratrace/ws                     WebSocket race test
POST /api/ratrace/microservice           Microservice race test
POST /api/ratrace/cache-race             Cache race test
POST /api/ratrace/state-fuzz             State fuzzing
POST /api/ratrace/orchestrate            Multi-step orchestration
GET  /api/ratrace/report/{id}            Generate report
POST /api/ratrace/graphql-subscription   GraphQL subscription race
POST /api/ratrace/oidc-logout            OIDC logout race

Intruder

GET  /api/intruder/attacks               List attacks
POST /api/intruder/attacks               Start an attack
GET  /api/intruder/attacks/{id}          Get attack details
DELETE /api/intruder/attacks/{id}        Delete attack
GET  /api/intruder/attacks/{id}/status   Attack status
POST /api/intruder/attacks/{id}/pause    Pause
POST /api/intruder/attacks/{id}/resume   Resume
POST /api/intruder/attacks/{id}/cancel   Cancel
GET  /api/intruder/attacks/{id}/results  Get results
GET  /api/intruder/generators            List payload generators
GET  /api/intruder/processors            List processing rules

Comparer

POST /api/comparer/compare       Compare two responses
POST /api/comparer/blind-detect  Blind vulnerability detection
GET  /api/comparer/similarity    Calculate similarity score

Extensions

GET  /api/extensions              List extensions
GET  /api/extensions/stats        Statistics
GET  /api/extensions/{id}         Get extension details
POST /api/extensions/{id}/load    Load
POST /api/extensions/{id}/unload  Unload
POST /api/extensions/{id}/enable  Enable
POST /api/extensions/{id}/disable Disable
POST /api/extensions/{id}/reload  Reload
POST /api/extensions/test-hook    Test a hook

Settings

GET    /api/settings/upstream-proxy          Get upstream proxy config
POST   /api/settings/upstream-proxy          Set upstream proxy
DELETE /api/settings/upstream-proxy          Clear upstream proxy
GET    /api/settings/upstream-proxy/rules    List proxy rules
POST   /api/settings/upstream-proxy/rules    Add proxy rule
PUT    /api/settings/upstream-proxy/rules    Replace all rules
DELETE /api/settings/upstream-proxy/rules/{id}  Remove rule
POST   /api/settings/upstream-proxy/test     Test proxy connection
POST   /api/settings/upstream-proxy/preset   Apply preset (tor, burp, mullvad, etc.)
GET    /api/settings/http2                   Get HTTP/2 config
POST   /api/settings/http2                   Set HTTP/2 config

Decoder

POST /api/decoder/encode              Encode data
POST /api/decoder/decode              Decode data
POST /api/decoder/chain               Chain encode/decode operations
POST /api/decoder/analyze             Analyze encoding layers
POST /api/decoder/reencode            Re-encode detected layers
POST /api/decoder/jwt/decode          Decode JWT
POST /api/decoder/jwt/forge           Forge JWT
POST /api/decoder/polyglot            Generate polyglot payloads
GET  /api/decoder/polyglot/contexts   List polyglot contexts
GET  /api/decoder/operations          List available operations

Assets

GET  /api/assets                       List assets
POST /api/assets                       Create asset
GET  /api/assets/stats                 Statistics
GET  /api/assets/coverage              Pipeline coverage
POST /api/assets/ingest/subflow        Ingest SubFlow results
POST /api/assets/ingest/xmass          Ingest XMass results
POST /api/assets/ingest/vmap           Ingest vmap results
POST /api/assets/crawl-seeds           Generate crawl seeds from assets
GET  /api/assets/cluster/jarm/{hash}   Cluster by JARM hash
GET  /api/assets/cluster/favicon/{mmh3} Cluster by favicon hash
GET  /api/assets/{id}                  Get asset
DELETE /api/assets/{id}                Delete asset
PATCH /api/assets/{id}                 Update asset
GET  /api/assets/{id}/ports            List ports
GET  /api/assets/{id}/events           List events

Intelligence

GET  /api/intelligence/params                   List discovered params
GET  /api/intelligence/params/search            Search params by name
GET  /api/intelligence/params/stats             Param statistics
GET  /api/intelligence/params/endpoint          Params for endpoint
GET  /api/intelligence/routes                   List routes
GET  /api/intelligence/routes/detail            Route details
GET  /api/intelligence/reflections              List reflected params
GET  /api/intelligence/reflections/candidates   XSS candidates
GET  /api/intelligence/reflections/stats        Reflection stats
GET  /api/intelligence/endpoints                List endpoints
GET  /api/intelligence/endpoints/detail         Endpoint details
GET  /api/intelligence/endpoints/stats          Endpoint stats
GET  /api/intelligence/rollups                  Security rollups
GET  /api/intelligence/rollups/summary          Rollup summary
GET  /api/intelligence/rollups/host/{host}      Host posture
POST /api/intelligence/analyze                  Analyze existing flows

Nerve (Parameter Analysis)

POST /api/nerve/analyze             Analyze parameters
POST /api/nerve/analyze-flows       Analyze params from flows
GET  /api/nerve/categories          List categories
GET  /api/nerve/categories/{short}  Category details
GET  /api/nerve/stats               Statistics

Collaboration (Pro)

POST /api/collab/share    Create shared session
POST /api/collab/join     Join via invite code
GET  /api/collab/status   Session status
POST /api/collab/leave    Leave session
POST /api/collab/publish  Publish annotation to partner

Access Tokens

GET    /api/tokens          List tokens
POST   /api/tokens/create   Create token
DELETE /api/tokens/{token}  Revoke token

License

GET  /api/license/status    License status
POST /api/license/account   Set account ID

External Tools

GET  /api/tools                  List registered tools
GET  /api/tools/health           Health check all tools
GET  /api/tools/{name}           Get tool info
GET  /api/tools/{name}/health    Health check one tool
POST /api/tools/{name}/execute   Execute tool command

Scheduler

GET    /api/scheduler/jobs              List jobs
POST   /api/scheduler/jobs              Create job
GET    /api/scheduler/jobs/{id}         Get job
PATCH  /api/scheduler/jobs/{id}         Update job
DELETE /api/scheduler/jobs/{id}         Delete job
POST   /api/scheduler/jobs/{id}/run     Trigger job
GET    /api/scheduler/jobs/{id}/runs    List run history

GraphQL

GET  /graphql    GraphQL Playground (HTML)
POST /graphql    GraphQL query/mutation endpoint

Real-time

GET /ws    WebSocket endpoint for real-time flow updates

Response Format

All API responses return JSON. Successful responses typically include the data directly. Errors return HTTP status codes:

  • 200 -- Success
  • 400 -- Bad request (invalid parameters)
  • 401 -- Unauthorized (auth required)
  • 404 -- Not found
  • 500 -- Internal server error

CORS

The API enables permissive CORS (all origins, all methods, all headers) to allow browser-based tooling to connect from any domain.

GraphQL API

Hugin exposes a GraphQL API primarily used by the desktop UI. It provides richer querying capabilities than the REST API for flow data -- multi-field filtering, sorting, pagination, and real-time subscriptions are all available in a single interface.

Endpoint

POST /graphql     Execute queries and mutations
GET  /graphql     GraphQL Playground (interactive browser IDE)

The GraphQL Playground is accessible at http://127.0.0.1:8081/graphql in a browser when the API server is running.

Schema

The schema is built with async-graphql and provides queries, mutations, and subscriptions.

Queries

flows -- List flows with filtering, sorting, and pagination.

query {
  flows(filter: {
    host: "example.com"
    method: "POST"
    statusCode: 200
    flagged: true
    limit: 50
    offset: 0
    sortBy: "created_at"
    sortOrder: "desc"
    createdAfter: "2026-03-01T00:00:00Z"
    minStatus: 200
    maxStatus: 299
    hasParams: true
    contentType: "application/json"
    tag: "auth"
  }) {
    flows {
      id
      method
      url
      host
      status
      contentType
      size
      latency
      flagged
      createdAt
    }
    total
    limit
    offset
    hasMore
  }
}

Filter fields:

  • method -- Filter by HTTP method
  • host -- Filter by hostname
  • urlContains -- Substring match on URL
  • statusCode -- Exact status code match
  • flagged -- Boolean filter for flagged flows
  • projectId -- Filter by project UUID
  • limit -- Results per page (default: 100)
  • offset -- Pagination offset (default: 0)
  • sortBy -- Sort column: created_at, method, host, status, latency, size
  • sortOrder -- asc or desc (default: desc)
  • createdAfter -- ISO 8601 timestamp lower bound
  • createdBefore -- ISO 8601 timestamp upper bound
  • minStatus / maxStatus -- Status code range
  • minLatencyMs -- Minimum response latency in milliseconds
  • hasParams -- Only flows whose URL contains ?
  • contentType -- Content-Type LIKE match
  • tag -- Flow must have this specific tag

flow -- Get a single flow by ID.

query {
  flow(id: "a3f2e1d0-...") {
    id
    method
    url
    host
    status
    requestHeaders
    responseHeaders
    requestBody
    responseBody
    latency
    flagged
    annotations
    createdAt
  }
}

stats -- Proxy statistics.

query {
  stats {
    totalFlows
    uniqueHosts
    totalSize
  }
}

Mutations

annotateFlow -- Flag, unflag, comment, or delete a flow.

mutation {
  annotateFlow(id: "a3f2...", action: FLAG, comment: "Interesting endpoint") {
    id
    flagged
  }
}

deleteFlow -- Delete a flow by ID.

mutation {
  deleteFlow(id: "a3f2...") {
    success
  }
}

Subscriptions

flowUpdates -- Real-time stream of new flows as they are captured by the proxy.

subscription {
  flowUpdates {
    id
    method
    url
    host
    status
    latency
    createdAt
  }
}

This subscription uses WebSocket transport (graphql-ws protocol). Connect to ws://127.0.0.1:8081/graphql with the graphql-transport-ws subprotocol.

Usage with curl

# Query flows
curl -X POST http://127.0.0.1:8081/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ flows(filter: { host: \"example.com\", limit: 10 }) { flows { id method url status } total } }"}'

# Get stats
curl -X POST http://127.0.0.1:8081/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ stats { totalFlows uniqueHosts } }"}'

Usage from JavaScript

const response = await fetch('http://127.0.0.1:8081/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: `
      query($host: String) {
        flows(filter: { host: $host, limit: 20 }) {
          flows { id method url status latency }
          total hasMore
        }
      }
    `,
    variables: { host: 'api.example.com' }
  })
});
const { data } = await response.json();

Authentication

When API authentication is enabled, include credentials in the request:

# Bearer token
curl -X POST http://host:8081/graphql \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ stats { totalFlows } }"}'

# Basic Auth
curl -X POST http://host:8081/graphql \
  -u "admin:password" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ stats { totalFlows } }"}'

REST vs GraphQL

The REST API and GraphQL API share the same underlying data store and service layer. Choose based on your use case:

  • REST: Simple CRUD, automation scripts, CI/CD integration, shell scripting
  • GraphQL: Complex queries with multiple filters, real-time subscriptions, UI integration, when you need precise control over returned fields

Authentication

Hugin has two distinct authentication systems:

  1. API authentication -- protects the HTTP API from unauthorized access when exposed on a network interface
  2. License authentication -- determines which features are available based on your account tier

API Authentication

When Is It Needed?

When running locally (bound to 127.0.0.1), authentication is disabled by default. Anyone with local access can use the API.

When bound to a network interface (0.0.0.0 or a specific IP), authentication should be enabled. Hugin logs a warning if it detects a non-loopback bind address without authentication enabled.

Authentication Methods

The API supports three authentication methods, checked in order:

1. Bearer Token (config-based)

A static token defined in the config file. Best for scripts and automation.

curl http://host:8081/api/flows \
  -H "Authorization: Bearer your-static-token"

Config:

[api]
auth_enabled = true
auth_token = "your-static-token"

2. Database Access Tokens (hgn_*)

Dynamic tokens stored in the database. Created and managed via CLI or API. Best for team collaboration where each member gets their own token.

# Create a token
hugin token create --label "alice"
# Output: hgn_a1b2c3d4e5f6...

# Use it
curl http://host:8081/api/flows \
  -H "Authorization: Bearer hgn_a1b2c3d4e5f6..."

# List tokens
hugin token list

# Revoke
hugin token revoke hgn_a1b2c3d4e5f6...

Token management API:

GET    /api/tokens          List all tokens
POST   /api/tokens/create   Create token (optional: label)
DELETE /api/tokens/{token}  Revoke token

3. HTTP Basic Auth

Username/password authentication. Useful when integrating with tools that only support Basic Auth.

curl http://host:8081/api/flows \
  -u "admin:secretpassword"

Config:

[api]
auth_enabled = true
auth_username = "admin"
auth_password = "secretpassword"

Unauthenticated Endpoints

The health check endpoint is always accessible without authentication, allowing monitoring tools and load balancers to verify the service is running:

GET /api/health    Always accessible (no auth)

Configuration

Full API authentication config in ~/.config/hugin/config.toml:

[api]
# Master switch for authentication
auth_enabled = false

# Basic Auth credentials
auth_username = "admin"
auth_password = "your-password"

# Static Bearer token
auth_token = "your-api-token"

Headless Server Mode

When running hugin serve for team collaboration, authentication is enabled by default (since it binds to 0.0.0.0). The --no-auth flag disables it but should only be used on trusted networks:

# Default: auth enabled, bind to 0.0.0.0
hugin serve --port 8080 --api-port 8081

# DANGEROUS: disable auth on trusted network only
hugin serve --no-auth

License Authentication

License authentication controls feature access, not API access. It is separate from API auth.

Tiers

  • Community (free): Proxy, scanner, intruder, sequencer, repeater, decoder, basic MCP tools
  • Pro (paid): Vurl MCP tools (49 offensive modules), Synaps WASM modules, RatRace, Lua extensions, multi-project, collaboration

Account Setup

# Set your account ID (format: HGN-XXXXXXXX-XXXXXXXX-XXXXXXXX)
hugin account set HGN-XXXXXXXX-XXXXXXXX-XXXXXXXX

# Check status
hugin account show

# Remove
hugin account clear

API:

GET  /api/license/status    Current license status and tier
POST /api/license/account   Set account ID

License Verification

License tokens are Ed25519 signed and verified locally. The license state refreshes periodically in the background. No phone-home for every API call -- verification is done at startup and on refresh intervals.

Security Recommendations

  • Always enable API auth when binding to non-loopback addresses
  • Use hgn_* database tokens for team members (revocable, auditable)
  • Keep the static Bearer token for automated systems where token rotation is impractical
  • When running hugin serve, ensure the API port is not publicly exposed without auth
  • Use TLS termination (e.g., Caddy or nginx reverse proxy) if exposing Hugin over the network

CLI Reference

Hugin ships as a single binary. Run without arguments to launch the desktop GUI. Run with a subcommand for CLI mode.

hugin              # Launch GUI
hugin <command>    # CLI mode

Global flags:

  • -v, --verbose -- Enable verbose logging (applies to all subcommands)

Commands

hugin start

Start the proxy daemon.

hugin start [OPTIONS]

Options:

  • -p, --port <PORT> -- Proxy listen port (default: 8080)
  • --api-port <PORT> -- API server port (default: 8081)
  • --bind <ADDRESS> -- Bind address (default: 127.0.0.1)
  • --mcp -- Also start the MCP server connected to the API

Example:

hugin start --port 8080 --api-port 8081 --mcp

hugin status

Show proxy status including whether it is running, the listen address, and basic statistics.

hugin status

hugin ca

Export the proxy CA certificate for browser/system trust store installation.

hugin ca [OPTIONS]

Options:

  • -o, --output <PATH> -- Output path for the certificate file
  • --print -- Print certificate to stdout (PEM format)

Example:

hugin ca -o ~/Hugin-CA.pem
hugin ca --print | sudo tee /usr/local/share/ca-certificates/hugin.crt

hugin flows

List captured HTTP flows.

hugin flows [OPTIONS]

Options:

  • -m, --method <METHOD> -- Filter by HTTP method (GET, POST, etc.)
  • --host <HOST> -- Filter by hostname
  • --flagged -- Show only flagged flows
  • -l, --limit <N> -- Maximum results (default: 20)
  • -f, --format <FORMAT> -- Output format: table or json (default: table)

Example:

hugin flows --host example.com --method POST --format json
hugin flows --flagged --limit 50

hugin flow

Show details of a specific flow by ID.

hugin flow <ID>

Example:

hugin flow a3f2e1d0-1234-5678-9abc-def012345678

hugin mcp

Start the embedded MCP server on stdio for integration with Claude Code and Claude Desktop. The MCP server starts its own proxy and API internally.

hugin mcp

This is the command specified in MCP client configurations:

{
  "mcpServers": {
    "hugin": {
      "command": "hugin",
      "args": ["mcp"]
    }
  }
}

hugin init

Generate a default configuration file at ~/.config/hugin/config.toml.

hugin init

hugin setup

First-run setup wizard. Configures CA certificate installation, browser proxy settings, and basic options.

hugin setup [OPTIONS]

Options:

  • --headless -- Non-interactive mode for CI/headless environments

hugin serve

Start a headless server for team collaboration. Binds to 0.0.0.0 by default for remote access. No GUI is launched.

hugin serve [OPTIONS]

Options:

  • -p, --port <PORT> -- Proxy listen port (default: 8080)
  • --api-port <PORT> -- API server port (default: 8081)
  • --bind <ADDRESS> -- Bind address (default: 0.0.0.0)
  • --no-auth -- Disable token authentication (DANGEROUS -- only use on trusted networks)

Example:

# Start headless server for team
hugin serve --port 8080 --api-port 8081

# On a trusted local network only
hugin serve --no-auth

hugin update

Check for updates or update Hugin in-place.

hugin update [OPTIONS]

Options:

  • --check -- Only check for updates, do not install

hugin verify

Verify the Ed25519 signature of a downloaded Hugin release file.

hugin verify <FILE> [OPTIONS]

Options:

  • -s, --sig <PATH> -- Path to the .sig file (defaults to <file>.sig)

Example:

hugin verify hugin-linux-amd64.tar.gz
hugin verify hugin-linux-amd64.tar.gz --sig custom-path.sig

hugin account

Manage your Hugin Pro license account.

hugin account set

Activate Pro license with your account ID.

hugin account set <ID>

The account ID format is HGN-XXXXXXXX-XXXXXXXX-XXXXXXXX (from your purchase confirmation).

hugin account show

Show current account and license status.

hugin account show

hugin account clear

Deactivate and remove the stored account ID.

hugin account clear

hugin scanner

Manage Synaps WASM scanner modules.

hugin scanner update

Sync modules from the community catalog.

hugin scanner update [OPTIONS]

Options:

  • --catalog-url <URL> -- Custom catalog URL (defaults to synaps-community GitHub)
  • --base-url <URL> -- Base URL for downloading WASM binaries
  • --dry-run -- Only check for updates, do not download

hugin scanner install

Install a specific module by ID.

hugin scanner install <ID> [OPTIONS]

Options:

  • --catalog-url <URL> -- Custom catalog URL
  • --base-url <URL> -- Base URL for WASM binaries

hugin scanner remove

Remove an installed module.

hugin scanner remove <ID>

hugin scanner list

List installed modules.

hugin scanner list

hugin config

Manage proxy configuration.

hugin config telemetry

Enable, disable, or check telemetry status.

hugin config telemetry [ACTION]

Action is on to enable, off to disable, or omit to show current status.

hugin config show

Show current configuration summary.

hugin config show

hugin plugin

Manage Lua plugins.

hugin plugin install

Install a plugin from a Git repository URL.

hugin plugin install <URL>

Example:

hugin plugin install https://github.com/user/hugin-plugin-name

hugin plugin remove

Remove an installed plugin by directory name.

hugin plugin remove <NAME>

hugin plugin list

List installed plugins.

hugin plugin list

hugin token

Manage access tokens for team collaboration.

hugin token create

Create a new access token.

hugin token create [OPTIONS]

Options:

  • -l, --label <LABEL> -- Optional label for the token (e.g., team member name)

hugin token list

List all access tokens.

hugin token list

hugin token revoke

Revoke an access token.

hugin token revoke <TOKEN>

The full hgn_* token string is required.

Configuration Reference

Hugin is configured via a TOML file at ~/.config/hugin/config.toml. Generate a default config with hugin init. If the file does not exist, Hugin uses built-in defaults.

File Locations

  • Config file: ~/.config/hugin/config.toml
  • CA certificate: ~/.config/hugin/Hugin-Proxy-CA.pem
  • CA private key: ~/.config/hugin/Hugin-Proxy-CA-key.pem
  • SQLite database: ~/.config/hugin/hugin.db
  • Extensions directory: ~/.config/hugin/extensions/

Configuration Sections

[proxy]

Controls the MITM proxy engine.

[proxy]
# Proxy listen address and port
listen_addr = "127.0.0.1:8080"

# API server address and port (optional, defaults to 127.0.0.1:8081)
api_addr = "127.0.0.1:8081"

# Upstream proxy URL for chaining (e.g., Tor, Burp, corporate proxy)
# upstream_proxy = "socks5://127.0.0.1:9050"

# Enable transparent (invisible) proxy mode — no browser config required
invisible_proxy = false

# Additional ports to bind the proxy on (e.g., for HTTPS interception)
additional_ports = []

# Per-host custom TLS certificate overrides
# [[proxy.per_host_certs]]
# host = "api.example.com"
# cert_path = "/path/to/cert.pem"

[ca]

Controls the Certificate Authority used for TLS interception.

[ca]
# Path to the CA certificate (PEM format)
cert_path = "~/.config/hugin/Hugin-Proxy-CA.pem"

# Path to the CA private key (PEM format)
key_path = "~/.config/hugin/Hugin-Proxy-CA-key.pem"

# Number of generated certificates to cache in memory
cache_size = 1000

[storage]

Controls data persistence.

[storage]
# SQLite database path
db_path = "~/.config/hugin/hugin.db"

# Maximum HTTP body size to store (bytes). Bodies exceeding this are truncated.
max_body_size = 10485760  # 10 MB

[scope]

Initial scope configuration. Scope is usually managed at runtime via the UI or MCP tools.

[scope]
# Hosts to include in scope (supports glob patterns)
include_hosts = ["*.example.com", "api.target.com"]

# Hosts to exclude from scope
exclude_hosts = ["analytics.example.com"]

[api]

API server authentication. See Authentication for details.

[api]
# Enable authentication (required when binding to non-loopback addresses)
auth_enabled = false

# Basic Auth credentials
auth_username = "admin"
auth_password = "your-password"

# Static Bearer token (alternative to Basic Auth)
auth_token = "your-api-token"

[http2]

HTTP/2 protocol settings for the proxy.

[http2]
# Enable HTTP/2 support
enabled = true

# ALPN protocols to advertise during TLS handshake
alpn_protocols = ["h2", "http/1.1"]

# Enable HTTP/2 server push handling
enable_server_push = true

# Maximum concurrent streams per connection
max_concurrent_streams = 100

# Initial window size for flow control (bytes)
initial_window_size = 65535

# Maximum frame size (bytes, must be 16384-16777215)
max_frame_size = 16384

# Enable HPACK header compression
enable_hpack = true

# Maximum header list size (bytes)
max_header_list_size = 16384

Per-host HTTP version overrides:

[[http2.host_overrides]]
pattern = "legacy.example.com"
http_version = "ForceHttp11"

[[http2.host_overrides]]
pattern = "*.modern.com"
http_version = "ForceHttp2"

HTTP version override values:

  • PreferHttp2 -- Prefer HTTP/2, fallback to HTTP/1.1
  • ForceHttp2 -- Force HTTP/2 only (fail if not supported)
  • ForceHttp11 -- Force HTTP/1.1 only
  • Auto -- Automatic negotiation (default)

[oastify]

Out-of-band interaction detection configuration. Connects to a remote Oastify server for DNS/HTTP callback tracking.

[oastify]
# Enable Oastify integration
enabled = false

# Base URL for Oastify API
base_url = "https://oastify.eu"

# DNS callback domain (if different from base_url host)
# domain = "oastify.eu"

# API token for authentication (optional)
# api_token = "your-token"

# Default session name for payload tracking
session = "default"

# Poll interval in milliseconds (minimum: 100)
poll_interval_ms = 5000

# Session time-to-live in hours (1-168)
session_ttl_hours = 24

[tools]

Paths and endpoints for external tool integrations.

[tools]
# Path to nerve binary (auto-detected from PATH if not set)
# nerve_path = "/usr/local/bin/nerve"

# Path to ghostcheck binary
# ghostcheck_path = "/usr/local/bin/ghostcheck"

# Path to rattrace binary
# rattrace_path = "/usr/local/bin/rattrace"

# XMass API endpoint
xmass_api = "http://127.0.0.1:8080"

# VectorSploit Hub gRPC endpoint
vectorsploit_hub = "http://127.0.0.1:50051"

# Path to subflow binary (auto-detected from PATH if not set)
# subflow_path = "/usr/local/bin/subflow"

[telemetry]

Anonymous telemetry configuration. See Telemetry for details.

[telemetry]
# Master switch (off by default)
enabled = false

# Telemetry backend endpoint
endpoint = "https://telemetry.hugin.nu/v1/events"

# Flush interval in seconds (minimum: 10)
flush_interval_secs = 300

# Maximum events buffered before eager flush (1-10000)
max_batch_size = 100

# Extra tags added to every event batch
# [telemetry.tags]
# team = "infra"

Full Default Config

Generate a complete default config:

hugin init

This writes ~/.config/hugin/config.toml with all default values and inline comments.

Runtime Configuration

Many settings can be changed at runtime without restarting Hugin:

  • Scope: Via MCP (scope tool), REST API (/api/scope), or the UI
  • Upstream proxy: Via MCP (settings tool), REST API (/api/settings/upstream-proxy), or the UI
  • HTTP/2 settings: Via MCP (settings tool) or REST API (/api/settings/http2)
  • Intercept rules: Via MCP (rules tool) or REST API (/api/rules)
  • Extensions: Via MCP (extensions tool), CLI (hugin plugin), or REST API (/api/extensions)
  • Telemetry: Via CLI (hugin config telemetry on/off)

Changes to the proxy listen address, CA certificate paths, and storage paths require a restart.

Environment Variables

  • HUGIN_CONFIG -- Override the config file path
  • HUGIN_LOG -- Set log level (e.g., debug, info, warn, error)
  • RUST_LOG -- Fine-grained log filtering (e.g., hugin_core=debug,hugin_mcp=info)

Architecture

Hugin is organized as a Rust workspace with 22 crates. Each crate has a focused responsibility. The entire system compiles to a single binary.

Single Binary, Three Modes

The hugin binary (built from the hugin-ui crate) operates in three modes:

  • No arguments: Launches the Dioxus desktop GUI
  • Subcommand: Runs the corresponding CLI handler (e.g., hugin start, hugin mcp)
  • hugin mcp: Starts the MCP server on stdio for AI assistant integration

Crate Map

hugin-shared          Shared types: HttpFlow, HttpRequest, ScopeConfig, transforms, diff
hugin-core            MITM proxy engine (hudsucker/hyper), interceptor chain, WebSocket
hugin-store           SQLite persistence (sqlx): flows, findings, projects, scope, rules
hugin-engine          Active scanner (23 checks), passive scanner, plugin bus
hugin-service         Business logic: repeater, intruder, decoder, session, sequencer,
                      intelligence, updater, telemetry
hugin-api             Axum REST (~200 endpoints) + async-graphql API server
hugin-ui              Unified binary: Dioxus desktop GUI + CLI (31 views, 16+ subcommands)
hugin-mcp             MCP server (126 tool modules: 42 base + 49 vurl + 35 advanced)
hugin-crawler         Web crawler (static + headless Chromium), JS analysis, form submission
hugin-oastify         OOB detection: DNS/HTTP/SMTP/LDAP/FTP/SMB listeners, payload generator
hugin-oastify-server  Standalone OOB callback server binary
hugin-extensions      Lua 5.4 plugin system (mlua), sandbox, permission model
hugin-ratrace         Race condition testing: barrier, last-byte, single-packet, 60+ modules
hugin-nerve           Passive response analysis: parameter discovery, pairs, parsers
hugin-scanner         WASM module system: feed compiler, DB loader, pattern matching
hugin-scanner-wasm    Wasmtime runtime for WASM scan modules
hugin-scanner-guest   Guest-side SDK for WASM module authors
hugin-scanner-cli     CLI for compiling/running/testing scan modules
hugin-browser         Browser automation: Chrome (CDP), Mullvad Browser (Marionette)
hugin-license         Ed25519 token verification, trial management, device fingerprinting
hugin-mobile          Android/iOS static analysis + Frida dynamic (library)
hugin-plugin-sdk      Plugin development SDK (traits + types, no runtime coupling)

Dependency Graph

hugin-ui (single binary)
├── hugin-api (REST + GraphQL server)
│   ├── hugin-service (business logic)
│   │   ├── hugin-store (SQLite persistence)
│   │   │   └── hugin-shared (types)
│   │   ├── hugin-core (MITM proxy engine)
│   │   │   └── hugin-shared
│   │   └── hugin-shared
│   ├── hugin-engine (scanner)
│   │   ├── hugin-service
│   │   └── hugin-shared
│   ├── hugin-extensions (Lua plugins)
│   ├── hugin-ratrace (race testing)
│   ├── hugin-nerve (passive analysis)
│   ├── hugin-oastify (OOB detection)
│   └── hugin-browser (Chrome/Mullvad)
├── hugin-mcp (MCP server)
│   ├── hugin-api (shares AppState)
│   └── vurl (offensive modules)
└── hugin-scanner (WASM modules)
    └── hugin-scanner-wasm (Wasmtime runtime)

Three Code Execution Systems

Hugin has three distinct code execution systems. Each serves a different purpose.

1. Native ActiveCheck (hugin-engine)

The built-in scanner. 23 vulnerability check types compiled into the binary. Users do not write these.

  • Trait: ActiveCheck in hugin-engine/src/scanner/active.rs
  • Registration: ScanExecutor::register_default_checks() in executor.rs
  • Capabilities: Payloads + analysis logic. The ScanExecutor handles HTTP sending, insertion point extraction, transform chain re-encoding, differential/blind detection, OOB callbacks, concurrency, rate limiting.
  • Not sandboxed (native Rust code). Not extensible by users at runtime.

2. WASM Modules -- Synaps (hugin-scanner)

Community scanner modules. Third-party Rust code compiled to WASM, sandboxed via Wasmtime.

  • Guest SDK: hugin-scanner-guest/src/imports.rs defines the Context trait with all host capabilities
  • Host runtime: hugin-scanner-wasm/src/host.rs implements host functions
  • Capabilities: HTTP, raw TCP, DNS, TLS inspection, WebSocket, browser automation, Oastify OOB, inter-module pipelines, SBB pattern matching, file read
  • Sandbox: WASM isolation, fuel-based execution limits (1 billion instructions), 16 MB memory cap
  • Loading: SBB database via ModuleLoader in hugin-scanner/src/db/loader.rs
  • The WASM compilation friction is intentional -- it provides a strong sandbox guarantee for untrusted community code

Users install modules via hugin scanner install <name>.

3. Lua Extensions (hugin-extensions)

User customization scripts. No compilation required.

  • API: hugin-extensions/src/lua_api.rs
  • Hooks: OnRequest, OnResponse, OnScanResult, OnFlowCapture, PassiveCheck, ActiveCheck
  • Unique capability: Only path that can modify traffic in-flight (change URL, headers, body, status, or drop)
  • Permissions: ReadFlows, ModifyFlows, NetworkAccess, FileSystem, SystemCommands
  • Sandbox: Lua debug hooks (10K instruction interval), 64 MB memory, 30s timeout, permission gating
  • Discovery: Auto-scans extensions directory for extension.json manifests

Key Data Types

  • HttpFlow -- A request-response pair with metadata (timing, flags, annotations, project). Defined in hugin-shared.
  • HuginStore -- SQLite persistence layer. All flows, findings, scope, rules, projects. In-memory mode for tests.
  • AppState -- Axum shared state. Contains the store, proxy handle, broadcast channels, all service instances. Shared across API, MCP, and UI via Arc.
  • ScanExecutor -- Scanner engine. Concurrent check execution with semaphore, rate limiting, pause/resume.
  • IntruderAttack -- Fuzzer run. Payload generators, processors, HTTP send, grep match/extract.
  • Project -- Workspace isolation. Flows, scope, findings, rules, repeater data. Exportable as .huginproject.

Desktop UI Architecture

The desktop app uses Dioxus and renders natively. Zero TCP -- all API calls go through tower::oneshot() on the in-process Axum Router, avoiding JSON serialization overhead for local operations.

BrowserMap = Arc<RwLock<HashMap<u16, BrowserSlot>>> -- shared across API, MCP, and UI. BrowserSlot holds either a Chrome manager (CDP) or a Mullvad session (Marionette).

MCP Architecture

The MCP server (hugin-mcp) uses Arc<AppState> directly -- zero HTTP, zero client abstraction. It shares the same service layer, store, and browser sessions as the GUI and REST API.

Communication is over stdio using the rmcp library. Responses are capped at 12,000 characters to avoid filling up the LLM context window.

Data Flow

Browser/Client
    │
    ▼
┌──────────────────┐
│   hugin-core     │  MITM Proxy Engine
│  (interceptor    │  ─── intercept queue (if intercept enabled)
│   chain)         │  ─── Lua extension hooks (OnRequest/OnResponse)
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│   hugin-store    │  SQLite: persist flow
│                  │  ─── Lua extension hooks (OnFlowCapture)
└──────┬───────────┘
       │
       ▼
┌──────────────────┐
│  hugin-engine    │  Passive scanner (background)
│  hugin-nerve     │  Parameter analysis, reflection detection
│  hugin-extensions│  Lua PassiveCheck hooks
└──────────────────┘
       │
       ▼
┌──────────────────┐
│  hugin-api       │  REST + GraphQL (external consumers)
│  hugin-mcp       │  MCP tools (AI assistants)
│  hugin-ui        │  Desktop GUI (Dioxus)
└──────────────────┘

Build

# Full workspace
cargo build --release

# Single binary (GUI + CLI)
cargo build --release --bin hugin

# All tests
cargo test --workspace

# API integration tests
cargo test -p hugin-api --test integration_tests

Linux build requires: libwebkit2gtk-4.1-dev, libgtk-3-dev, libayatana-appindicator3-dev.

WASM modules build separately:

cd synaps-modules/example
cargo build --target wasm32-unknown-unknown --release

External Dependencies

  • vurl -- Private repo at ../vurl, referenced as vurl = { path = "../vurl" }. CI needs VURL_PAT secret.
  • SQLite -- Embedded via sqlx. No external database server needed.
  • Chromium -- Optional, for headless crawling and browser automation. Feature-gated.

Telemetry

Hugin includes an optional, anonymous telemetry system to help prioritize development.

Privacy

  • Off by default -- must be explicitly enabled
  • No PII -- no URLs, IPs, hostnames, request content, findings, or credentials
  • No tracking -- installation ID is a random UUID, not linked to any account
  • Open source -- the telemetry code is in hugin-service/src/telemetry.rs
  • No phone-home -- when disabled, zero network requests are made to the telemetry backend

What Is Collected

When enabled, Hugin sends anonymous usage events:

  • Feature usage counts -- which tools are used (e.g., "scanner started", "intruder run") without any target information
  • Version and platform -- Hugin version, OS, architecture
  • Session duration -- how long the application was running
  • Error counts -- crash/error type counts (no stack traces or context)

What is never collected:

  • URLs, hostnames, or IP addresses
  • Request/response content
  • Scanner findings or vulnerability details
  • Account IDs or license keys
  • File paths or system information beyond OS/arch

Enabling/Disabling

Via CLI

# Check current status
hugin config telemetry

# Enable
hugin config telemetry on

# Disable
hugin config telemetry off

Via Config File

Edit ~/.config/hugin/config.toml:

[telemetry]
enabled = false

Configuration

Full telemetry configuration options:

[telemetry]
# Master switch
enabled = false

# Backend endpoint
endpoint = "https://telemetry.hugin.nu/v1/events"

# How often to flush buffered events (seconds, minimum: 10)
flush_interval_secs = 300

# Maximum events to buffer before eager flush (1-10000)
max_batch_size = 100

# Extra key-value tags added to every event batch
[telemetry.tags]
# team = "security"
# environment = "lab"

Data Flow

When enabled:

  1. Usage events are buffered in memory
  2. Every flush_interval_secs seconds (default: 5 minutes), or when the buffer reaches max_batch_size, events are sent as a single HTTP POST to the configured endpoint
  3. If the endpoint is unreachable, events are silently dropped (no retry, no local persistence)
  4. On clean shutdown, remaining buffered events are flushed

Self-Hosted Telemetry

For teams that want usage analytics without sending data externally, point the endpoint to your own server:

[telemetry]
enabled = true
endpoint = "https://your-internal-server.example.com/v1/events"

[telemetry.tags]
team = "appsec"

The event format is a JSON array of event objects. See hugin-service/src/telemetry.rs for the exact schema.

Changelog

0.1.0 (Unreleased)

Initial release.

  • MITM proxy with HTTP/1.1, HTTP/2, and WebSocket support
  • Core tools: Repeater, Intruder, Sequencer, Decoder, Comparer, Match & Replace
  • Synaps WASM scanner with community module marketplace
  • Active scanner (vurl) with SSRF, SQLi, SSTI, XSS, BOLA, JWT, LDAP checks
  • Nerve passive intelligence (parameter discovery, tech fingerprinting)
  • RatRace race condition testing engine
  • Oastify out-of-band detection
  • Web crawler with headless browser support
  • Lua plugin system
  • MCP server with 94 tools for Claude integration
  • REST + GraphQL API
  • Desktop GUI (Dioxus)
  • Self-update mechanism
  • Community module auto-update
  • First-run onboarding wizard
  • Opt-in anonymous telemetry