Mastering mitmproxy: A Hands-on Guide to HTTPS Inspection and API Debugging

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Peering Inside the HTTPS Black Box

Modern web traffic is almost entirely encrypted. While this is a massive win for user privacy, it creates a massive headache for developers. When an API returns a cryptic error or a mobile app behaves unexpectedly, you can’t just ‘peek’ at the packets. You’re left staring at a wall of ciphertext. This is why mitmproxy is the first tool I reach for when I need to see what’s actually happening under the hood.

Think of it as a much more powerful version of the Chrome ‘Network’ tab. It doesn’t just show you browser requests; it intercepts traffic from any source—mobile apps, CLI tools, or backend microservices. Whether you are debugging HTTP/2 streams or inspecting WebSockets, mitmproxy gives you total control over the data flow.

The 5-Minute Setup

Getting mitmproxy up and running is surprisingly fast. I prefer using package managers because they handle Python dependencies automatically, saving you from version conflicts later on.

1. Installation

On macOS, Homebrew is the path of least resistance. For Linux users, pipx is the gold standard for keeping your system environment clean.

# macOS
brew install mitmproxy

# Linux (Ubuntu/Debian)
sudo apt update && sudo apt install mitmproxy

2. Picking Your Interface

Mitmproxy comes in three flavors. mitmproxy provides a classic terminal UI (TUI). mitmweb launches a browser-based dashboard. mitmdump works like tcpdump but for HTTP. For 90% of my work, the terminal interface is the fastest way to filter through thousands of requests.

mitmproxy

The proxy starts listening on port 8080 by default. You can change this using -p 8888 if you have another service already occupying that port.

3. Routing Your Traffic

Point your device or browser to localhost:8080. At this point, HTTP sites will load, but HTTPS sites will trigger a “Your connection is not private” warning. This happens because your device (rightly) doesn’t trust the proxy’s self-signed certificate yet.

Configuring SSL Inspection (The ‘Magic’ Part)

To decrypt traffic, mitmproxy generates a dummy certificate for every site you visit. Your device needs to recognize mitmproxy as a trusted Certificate Authority (CA).

Installing the CA Certificate

With the proxy running, open your browser and go to mitm.it. This page detects your OS and offers the correct certificate download.

  • Windows/macOS: Install the certificate and move it to the “Trusted Root Certification Authorities” store.
  • Android: Since Android 7.0, apps ignore user-installed certificates by default. You may need a rooted device or a patched APK to bypass this restriction.
  • iOS: Download the profile, then navigate to Settings > General > About > Certificate Trust Settings. You must manually toggle the switch for mitmproxy to “Full Trust.”

A Note on Infrastructure Security

If you’re running mitmproxy on a remote server for team testing, don’t leave it wide open. Unprotected proxies are quickly found by bots and used for malicious traffic. I always use strong authentication for my .htpasswd files. To generate these, I use the password generator at toolcraft.app. It’s a client-side tool, meaning your keys and passwords never leave your browser, making it safe for generating sensitive server credentials.

Interception and Scripting

The real fun begins when you stop just watching and start manipulating traffic.

1. Live Interception

In the console, hit the i key to set an intercept filter. If I want to pause every request going to a specific login endpoint, I use:

# Set filter:
~u /v1/auth/login

The request will turn orange and pause in transit. You can then press e to edit the JSON body—perhaps to change a user_role from “guest” to “admin”—and press a to resume. This is a game-changer for testing how your backend handles malicious or malformed data.

2. Automating with Python

Manual editing is slow. If you need to inject a specific header into every single response, write a simple script. Here is a 10-line snippet I use to simulate security headers or modify server responses on the fly.

from mitmproxy import http

def response(flow: http.HTTPFlow) -> None:
    # Inject a custom header for tracking
    flow.response.headers["X-Audit-ID"] = "12345-DEBUG"
    
    # Simulate a UI change by replacing text
    if "Welcome" in flow.response.get_text():
        flow.response.set_text(flow.response.get_text().replace("Welcome", "Access Granted"))

Launch it with: mitmproxy -s modify_traffic.py.

3. Essential Filter Shortcuts

Don’t drown in noise. Use these filters to find the needle in the haystack:

  • ~m post: Only show POST requests.
  • ~c 500: Find those annoying internal server errors instantly.
  • ~b "token": Scan request/response bodies for specific strings like JWTs or API keys.
  • !(~u analytics): Hide all the tracking noise from Google or Mixpanel.

Practical Lessons from the Field

I’ve used mitmproxy for hundreds of hours of security audits. Here is what I’ve learned the hard way.

Bypassing Certificate Pinning: High-security apps (like banking or social media) use SSL Pinning. They ignore your system’s trust store. If you see “Client Handshake Failed” in your logs, you’ll need to use Frida or Objection to disable pinning logic inside the app before mitmproxy can see the traffic.

Memory Management: Mitmproxy stores every single ‘flow’ in RAM. If you leave it running for a full day of heavy browsing, it can easily climb to 1GB of memory usage. Hit the z key regularly to clear the buffer and keep the interface responsive.

Cleanup: Never leave a proxy CA certificate installed on your primary machine longer than necessary. It is a massive security risk. I recommend using a dedicated “Dirty” browser profile or a Virtual Machine for your testing sessions to keep your personal banking and email safe.

Collaboration: Found a bug? Use the W key to save the specific flow to a file. You can Slack that file to a teammate, and they can load it with mitmproxy -r bug_report.flow to see the exact headers, timing, and payload you discovered.

Mitmproxy turns the “black box” of HTTPS into a clear, editable stream. It transforms the way you debug, moving you from blind guessing to data-driven fixes.

Share: