Skip to content
 
 

Repository files navigation

mitmproxy

Continuous Integration Status

mitmproxy is an interactive, SSL/TLS-capable intercepting proxy with interfaces for HTTP/1, HTTP/2, WebSockets, and more.

  • mitmproxy — interactive terminal interface
  • mitmdump — command-line capture and replay interface
  • mitmweb — web interface

Install and general documentation are available at mitmproxy.org and docs.mitmproxy.org. To develop from source, read CONTRIBUTING.md.

Firetoll

This fork includes Firetoll: an observe-only traffic enrichment layer that makes a mitmproxy session queryable by a human or an AI agent. It adds process attribution, detector-backed findings, privacy-aware session storage, terminal/JSON/Markdown reports, and a separate MCP server.

Firetoll never changes proxied traffic. A detector failure is isolated and cannot fail a flow. Findings are attached to flow.metadata["firetoll.findings"], so they survive .mitm serialization.

Quick start

Run the proxy separately from the MCP server. Firetoll is enabled by default and writes its session database to ~/.mitmproxy/firetoll/session.sqlite.

uv run mitmdump

The regular proxy listens on http://127.0.0.1:8080. Applications must be explicitly configured to use it; starting firetoll-mcp does not start a proxy listener or discover applications by itself. For example, configure a terminal shell and the commands launched from it with:

export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"

On macOS, HTTPS clients must trust mitmproxy's interception CA. After the proxy has generated ~/.mitmproxy/mitmproxy-ca-cert.pem, trust it in the login keychain:

security add-trusted-cert \
  -d \
  -r trustRoot \
  -k "$HOME/Library/Keychains/login.keychain-db" \
  "$HOME/.mitmproxy/mitmproxy-ca-cert.pem"

Restart the client after installing the CA. An UnknownIssuer error means the application reached the proxy but does not yet trust this certificate.

OpenAI Codex CLI

The codex command starts a native Rust binary behind its Node launcher. As a result, NODE_EXTRA_CA_CERTS alone is not sufficient for Codex to trust the mitmproxy CA; install the CA in the macOS login keychain as shown above, then fully quit and restart Codex. Other terminal clients may instead honor NODE_EXTRA_CA_CERTS or another client-specific CA-bundle variable.

Other agent CLIs (e.g. Hermes)

Many Python-based agent CLIs build their own httpx/requests client and resolve a custom CA bundle from an environment variable rather than reading the OS trust store, so installing the CA in the keychain above is not sufficient for them. Check the client's docs or source for an app-specific variable (e.g. Hermes reads HERMES_CA_BUNDLE) before falling back to the more common SSL_CERT_FILE or REQUESTS_CA_BUNDLE:

export HERMES_CA_BUNDLE="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"

Set this in the same shell before launching the client; no keychain changes or restart are needed since the client reads the file directly.

For an opt-in zsh setup, add this block to ~/.zshrc and open a new shell:

export MITMPROXY_ENABLED=0
if [[ "$MITMPROXY_ENABLED" == "1" ]]; then
  export HTTP_PROXY="http://127.0.0.1:8080"
  export HTTPS_PROXY="$HTTP_PROXY"
  export ALL_PROXY="$HTTP_PROXY"
  export http_proxy="$HTTP_PROXY"
  export https_proxy="$HTTPS_PROXY"
  export all_proxy="$ALL_PROXY"
else
  unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy
fi

Set MITMPROXY_ENABLED=1 to enable proxying for newly opened shells, or MITMPROXY_ENABLED=0 to disable it. The terminal emulator itself is not the traffic source; commands and applications launched from its shell inherit the proxy environment.

To verify the path without relying on an application-specific client:

curl https://example.com

During an interactive session, use firetoll.report. To export both formats, set a base path:

mitmdump \
  --set firetoll_report=true \
  --set firetoll_report_path=/tmp/firetoll-session

This writes /tmp/firetoll-session.json and /tmp/firetoll-session.md.

MCP access

firetoll-mcp is a separate stdio process. It opens the SQLite store read-only, never runs in the proxy data path, and cannot broaden the capture policy after the session was recorded. Enable it only when a session exists and you intend to expose that session to an agent.

uv run firetoll-mcp --store-path ~/.mitmproxy/firetoll/session.sqlite

Two checked-in, per-agent config files wire up the same uv run firetoll-mcp server so it works out of the box in either coding tool, gated behind that tool's own opt-in mechanism:

  • Codex: .codex/config.toml defines the firetoll server with enabled = false. Flip it to true to use it.
  • Claude Code: .mcp.json defines the same server. Claude Code prompts to approve project-scoped MCP servers the first time they're used, which is the equivalent opt-in gate.

The server provides tools for session totals, attributed applications, flow queries, evidence-backed findings, identity joins, AI-agent activity, x402 offers, redaction rules, stored body metadata, bounded body reads, and the tool-call audit log. get_body returns a 4 KiB window by default; use offset and limit or get_body_range for explicit bounded reads. list_bodies returns metadata without content. Reads are capped at 64 KiB per call.

Every tool call - not only get_body - is written to tool_log, readable through the tool_log tool or, without needing the MCP server running at all, via firetoll audit below. session_overview reports is_live and session_id for the run currently being written to, plus a list of every known session, so an agent orienting itself can never mistake a live capture for a finished one or a multi-run total for a single session's traffic. get_body/list_bodies also return each body's sha256 (and, for a bounded read, range_sha256 for exactly the bytes returned) so a specific claim can be checked against a fingerprint instead of taken on trust.

Auditing the agent without asking it

firetoll is a separate, read-only console script over the same store, usable whether or not firetoll-mcp is running:

uv run firetoll sessions
uv run firetoll audit
uv run firetoll flows --host api.anthropic.com
uv run firetoll bodies --flow-id <id>

firetoll audit prints tool_log directly from the SQLite file. This is deliberate: an MCP server auditing itself, or an agent reporting its own past reads, is not independent evidence. firetoll audit reads the same file a raw sqlite3/python3 -c 'import sqlite3...' script would, which is also the honest limit of any of this: a process with filesystem access to the store can always read it directly, and that read will never appear in tool_log. session_overview's limits field says so explicitly rather than implying a guarantee this design can't make.

What Firetoll detects

  • Telemetry and analytics sinks, including corpus signatures and JSON event heuristics.
  • AI-agent egress, including provider requests, MCP JSON-RPC, model identifiers, byte counts, and WebSocket upgrade handshakes.
  • Trackers and identity joins: the same identifier observed across multiple eTLD+1 domains.
  • Bot detection and fingerprinting signals, plus a stable TLS client-profile hash.
  • x402 402 Payment Required offers, with normalized network identifiers and a dry-run cost quote.

Each finding has a class, label, confidence (signature or heuristic), and non-empty evidence describing the header, path, or body key that triggered it.

Privacy and evidence boundaries

Metadata and findings are stored by default; bodies are not. Enable bounded body capture explicitly:

mitmdump \
  --set firetoll_store_bodies=true \
  --set firetoll_body_access=redacted

redacted removes prompt/completion fields, secret-named JSON fields, common credentials, emails, IP addresses, phone numbers, and card-shaped values before storage. Captured bodies are capped at 64 KiB. full stores raw bodies and is intended only for a deliberate, audited local workflow; MCP body reads are logged. none refuses body reads even when bodies exist.

The report explicitly counts unattributed flows, CONNECT-only flows, streamed bodies, truncation, and the fact that WebSocket frame capture is off by default. An absent finding means “not observed by this capture configuration,” not “safe” or “not present.”

The store is mode 0600, its directory is mode 0700, identifier values are salted and hashed, and rows older than firetoll_retention_hours (24 by default) are deleted on startup and during periodic sweeps. To erase the current session, run firetoll.wipe.

Options

Option Default Purpose
firetoll true Enable enrichment, storage, and commands.
firetoll_attribution true Resolve client sockets to local processes; fall back to User-Agent.
firetoll_store_bodies false Capture request/response bodies after applying the selected access policy.
firetoll_body_access redacted MCP body policy: none, redacted, or full.
firetoll_retention_hours 24 Retention window for stored flow data.
firetoll_corpus_dir empty Directory containing additional telemetry.yaml and trackers.yaml files.
firetoll_report false Print a report when the proxy exits.
firetoll_report_path empty Base path for JSON and Markdown exports.
firetoll_store_path platform default Override the SQLite path.

Corpus files are data, not code. Bundled corpora can be extended at runtime with --set firetoll_corpus_dir=/path/to/corpus; supplied files are merged with the bundled files.

x402 boundary

Firetoll decodes common x402 offer shapes, maps known network names to CAIP-2 identifiers, renders offers in the content view, and exposes a dry-run quote. It does not hold keys, sign authorizations, submit transactions, inject payment headers, replay requests, or claim settlement. The x402 feature is an observation and explanation layer.

Source layout

mitmproxy/firetoll/
  attribution.py       client connection → process/User-Agent attribution
  classify/             telemetry, agent-egress, tracker, and bot detectors
  enrich.py             detector orchestration and flow metadata
  finding.py            evidence-backed finding contract
  redact.py             body redaction and 64 KiB cap
  store.py              permissioned SQLite store and retention
  report.py             terminal, JSON, and Markdown reports
  x402.py               offer parsing, detection, and dry-run quotes
  x402_contentview.py   x402 content view
  mcp/server.py         separate read-only stdio MCP server
  cli.py                separate read-only console script (`firetoll`), no MCP dependency
  data/                 bundled detector corpora
test/mitmproxy/firetoll/ Firetoll unit and integration tests

The Firetoll CI job enforces a small upstream diff budget. New feature code and tests belong under the two Firetoll directories; core wiring is limited to the documented addon/contentview registration, packaging, repository documentation, workflow, and budget-check files.

About

An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages