1.068 API Proxy / MITM Frameworks#
Explainer
Domain Explainer: API Proxy and MITM Frameworks#
What Is a Proxy?#
A proxy is a middleman for network traffic. Instead of your application connecting directly to a server, it connects to the proxy, which forwards the request and returns the response. The proxy can inspect, modify, block, or log any traffic passing through it.
There are three distinct proxy models that get confused:
Explicit proxy: The client knows about the proxy and is configured to use it. You set HTTP_PROXY=http://localhost:8080 and every HTTP library in that process routes through the proxy. Easy to set up; requires configuring each client.
Reverse proxy: The proxy impersonates the server. Clients connect to the proxy’s address, not the real server. nginx, Traefik, and Envoy in front of web services are reverse proxies. The client doesn’t know it’s talking to a proxy.
Transparent proxy: Traffic is redirected to the proxy at the OS/network level, with no client configuration. The client thinks it’s connecting directly to the destination. Requires Linux kernel mechanisms (iptables, TPROXY) or acting as the network gateway.
What Is MITM (Man-in-the-Middle)?#
In the context of proxy tools, MITM refers to intercepting encrypted (HTTPS/TLS) traffic. Normally, TLS prevents a proxy from reading HTTPS content — the proxy sees encrypted bytes it can’t decrypt.
MITM proxies break this by performing “split TLS”:
- The client makes a TLS connection to the proxy
- The proxy presents a fake certificate for the real server (signed by its own CA)
- The proxy makes its own TLS connection to the real server
- The proxy can now read and modify the plaintext between the two encrypted connections
The catch: This only works if the client trusts the proxy’s CA. For devices you control (your laptop, test devices), you install the proxy’s CA certificate as trusted. For devices you don’t control, you can’t intercept TLS — that’s the security guarantee TLS provides.
mitmproxy: The Python Tool#
mitmproxy is the canonical Python MITM proxy. You write Python addons — classes with hook methods that get called for each HTTP request and response:
class MyAddon:
def request(self, flow):
# Called for every request before it's sent upstream
flow.request.headers["X-My-Header"] = "injected"
def response(self, flow):
# Called for every response before it's sent to the client
if flow.response.status_code == 404:
flow.response = make_mock_response()This is powerful for:
- Mocking API responses in development/testing
- Security testing — fuzzing parameters, injecting payloads
- Recording traffic and replaying it later
- Debugging — seeing exactly what your app sends and receives
mitmproxy has three interfaces: an interactive terminal UI (mitmproxy), a non-interactive scriptable CLI (mitmdump), and a browser-based UI (mitmweb).
Transparent Proxy Without Client Config#
The most powerful (and complex) scenario: intercepting traffic from a device or process without touching its configuration.
How it works:
- Linux
iptablesrules redirect traffic destined for port 80/443 to the proxy port instead - The proxy uses
SO_ORIGINAL_DSTto find out where the traffic was originally going - The proxy establishes its own connection to the real destination
- Traffic flows through the proxy invisibly
This is what penetration testers use to intercept mobile app traffic: put your device on a WiFi hotspot you control, add iptables rules, and all traffic routes through mitmproxy.
Production Proxies vs Development Proxies#
Development/testing (mitmproxy): Python-scriptable, full body access, interactive UI. Adds 5-50ms latency per request. Never use in production traffic paths.
Production (Envoy, Traefik, nginx): Optimized for throughput. Sub-millisecond overhead. Extension via compiled languages (Lua, WASM, Go plugins). Not scriptable in Python directly.
Envoy is the backbone of modern service meshes (Istio, Consul Connect). It runs as a sidecar next to every microservice container, intercepting all traffic. Config is YAML; extensions are Lua scripts or compiled WASM modules.
Traefik is simpler than Envoy. Defines routes and middleware via Docker labels or Kubernetes annotations. Automatically provisions HTTPS via Let’s Encrypt. Better choice for teams that don’t need Envoy’s complexity.
Certificate Pinning#
Some apps hardcode the expected certificate and refuse to connect if they get any other cert — even one signed by a trusted CA. This breaks mitmproxy’s MITM approach.
Where you encounter it: Banking apps, payment apps, some enterprise mobile apps.
Bypass (for apps you own/test): Use Frida to hook the SSL verification function at runtime, making it accept any certificate. Requires rooting the device.
For your own apps: Disable pinning in debug builds. Enable it only in production/release builds.
eBPF: The Emerging Alternative#
eBPF is a Linux kernel technology that allows running sandboxed programs inside the kernel. Tools like Cilium use eBPF for network proxying with dramatically lower overhead than userspace proxies — down to microseconds vs milliseconds for Envoy.
For 2026, eBPF-based proxying (especially via Cilium in Kubernetes) is production-ready for L3/L4 but limited at L7. Within a few years, eBPF may reduce or eliminate the need for Envoy sidecar proxies in high-performance environments.
What This Domain Is NOT#
- VPN: Routes all traffic through an encrypted tunnel to a remote endpoint. Not designed for traffic inspection — the VPN provider sees plaintext.
- Load balancer: Distributes traffic across servers. Proxies traffic but typically doesn’t inspect/modify it at the application layer.
- Firewall: Blocks traffic based on rules. Doesn’t read or modify application-layer content.
- Service mesh: An architectural pattern; Envoy is the common proxy implementation within a service mesh.
S1: Rapid Discovery
S1 Approach: Rapid Discovery#
Objective: Map the API proxy and MITM framework ecosystem. Distinguish the tool tiers: Python scriptable proxies, service mesh proxies, and OS-level transparent interception.
Topics examined:
- mitmproxy: Python scriptable MITM proxy (modes, addon API, TLS)
- proxy.py: lightweight Python alternative
- Envoy: C++ service proxy with xDS/WASM/Lua extension APIs
- Traefik: Go-based reverse proxy with middleware plugins
- iptables/TPROXY: OS-level transparent proxy (no client config required)
- Comparison with commercial tools (Burp Suite, Charles, Fiddler)
- Key taxonomy: intercepting proxy vs reverse proxy vs transparent proxy
S1 Overview: API Proxy / MITM Frameworks#
Taxonomy First#
Three distinct proxy models, often confused:
Explicit (intercepting) proxy: Client is configured to use the proxy (e.g., HTTP_PROXY=http://localhost:8080). Client sends CONNECT tunnels for HTTPS. mitmproxy’s default mode.
Reverse proxy: Proxy sits in front of a server. Client connects to the proxy thinking it’s the real server. Traefik, nginx, Envoy in typical deployment.
Transparent proxy: Traffic is redirected to the proxy at the network/OS level — the client is unaware. Requires iptables/TPROXY or similar OS routing. mitmproxy’s transparent mode.
Python MITM Tools#
mitmproxy#
GitHub: mitmproxy/mitmproxy | ~41.5K stars | PyPI: mitmproxy | ~3M downloads/month
Version: 12.2.1 (Feb 2026) | Language: Python + Go (wireguard core)
The canonical Python MITM proxy. Three interfaces:
mitmproxy— interactive terminal UImitmdump— non-interactive, for scriptsmitmweb— browser-based UI
Python addon API (the key feature):
# addon.py
from mitmproxy import http
class ModifyHeaders:
def request(self, flow: http.HTTPFlow):
flow.request.headers["X-Custom"] = "injected"
def response(self, flow: http.HTTPFlow):
if "sensitive" in flow.response.text:
flow.response.text = flow.response.text.replace("sensitive", "REDACTED")
addons = [ModifyHeaders()]Run: mitmdump -s addon.py
TLS: mitmproxy generates a self-signed CA cert on first run (~/.mitmproxy/mitmproxy-ca.pem). For HTTPS interception, install this cert as trusted CA on the client.
Transparent mode: Requires iptables/TPROXY routing (see OS-level section).
proxy.py#
GitHub: abhinavsingh/proxy.py | ~11K stars | PyPI: proxy.py
Language: Pure Python, single file originally
Lighter-weight alternative. Plugin-based. Better suited for performance testing and simple interception. Less feature-rich than mitmproxy.
Service Mesh / Infrastructure Proxies#
Envoy#
GitHub: envoyproxy/envoy | ~25K stars | Language: C++ Backing: CNCF (Cloud Native Computing Foundation), Google, Lyft origin
Envoy is a high-performance L7 proxy designed for service mesh deployments. It is NOT a MITM tool for security testing — it’s infrastructure.
Extension models:
- HTTP filters (Lua): Simple scripting in Lua, runs in-process
- HTTP filters (WASM): Compiled WASM modules (Go, Rust, C++, AssemblyScript), higher capability
- External processing filter: HTTP sidecar that calls out to an external gRPC service for request/response modification
xDS API: Envoy’s control plane protocol. Management servers (Istio, Consul, custom) push configuration to Envoy instances dynamically.
Typical deployment: One Envoy sidecar per container in Kubernetes (Istio/Envoy mesh), or as a standalone edge/gateway proxy.
Traefik#
GitHub: traefik/traefik | ~53K stars | Language: Go Backing: Traefik Labs (commercial company)
Reverse proxy and load balancer with automatic HTTPS and service discovery. Docker/Kubernetes-native via label-based config.
Middleware plugin system:
# traefik.yml
http:
middlewares:
my-plugin:
plugin:
myPlugin:
headerName: "X-Custom"
headerValue: "injected"Plugins are Go code compiled at startup. Not Python.
OS-Level: iptables / TPROXY#
Transparent proxy requires redirecting traffic to the proxy process without the client knowing. Linux mechanism: TPROXY.
# Redirect all TCP port 80/443 to mitmproxy on port 8080
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
--tproxy-mark 1 --on-port 8080
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j TPROXY \
--tproxy-mark 1 --on-port 8080
# Route marked packets through loopback
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100mitmproxy then uses SO_ORIGINAL_DST to determine the original destination and establishes a TLS connection to it.
Quick Verdict Table#
| Tool | Language | Use Case | Verdict |
|---|---|---|---|
| mitmproxy | Python | Development, security testing, scripted interception | ✅ Best path for Python |
| proxy.py | Python | Lightweight plugin-based proxy | ✅ Simpler alternative |
| Envoy | C++ | Production service mesh, high-performance L7 proxy | ✅ For infrastructure |
| Traefik | Go | Reverse proxy with Docker/K8s auto-discovery | ✅ For reverse proxy needs |
| iptables/TPROXY | Linux | Transparent redirect (used with mitmproxy) | ✅ OS-level technique |
| Burp Suite | Java | Security testing (commercial) | ⚠️ Commercial, no Python API |
| Charles Proxy | Java | Mac-friendly GUI proxy | ⚠️ Commercial, GUI only |
S1 Recommendation: Rapid Discovery#
Preliminary Winners#
| Use Case | Tool | Language |
|---|---|---|
| Python-scriptable HTTP/HTTPS interception | mitmproxy | Python |
| Lightweight Python proxy plugin | proxy.py | Python |
| Production service mesh proxy | Envoy | C++ |
| Reverse proxy with auto-discovery | Traefik | Go |
| Transparent OS-level redirect | iptables + TPROXY | Linux |
| GUI-based security testing | Burp Suite (commercial) | Java |
Confidence#
High on mitmproxy (dominant Python MITM tool, active development). High on Envoy for infrastructure (CNCF standard, Google/Lyft backing). Medium on Traefik (good tool, less relevant for MITM use cases specifically). Medium on proxy.py (simpler but less battle-tested than mitmproxy).
S1 Synthesis: API Proxy / MITM Frameworks#
Key Findings#
mitmproxy is the Python answer: 38K stars, Python addon API with request/response hooks, three interface modes (TUI, CLI, web). The canonical tool for Python-scriptable HTTP/HTTPS interception.
Two distinct audiences, two different tools: mitmproxy is for developers and security testers (debugging, testing, fuzzing). Envoy/Traefik are for infrastructure teams building service meshes and production traffic routing. Don’t confuse them.
Transparent proxy is an OS concern: mitmproxy handles the HTTP layer; iptables/TPROXY handles the routing. The combination enables interception without any client configuration changes.
TLS interception requires trust: HTTPS interception requires installing mitmproxy’s CA cert as trusted on the client. This is routine for devices you control; impossible (by design) for devices you don’t.
Envoy extension model is layered: Lua for simple scripts, WASM for complex compiled logic, external processing gRPC for stateful/external-service-dependent logic.
What S2 Should Investigate#
- mitmproxy addon API hooks in depth: request, response, tls_start_client, websocket hooks
- HTTP/2 and gRPC proxying capability in mitmproxy and Envoy
- Certificate pinning bypass techniques
- TPROXY setup in Docker/container networking
- Performance overhead benchmarks
- proxy.py plugin API compared to mitmproxy addons
- Envoy WASM filter development workflow
S2: Comprehensive
S2 Approach: Comprehensive Analysis#
Objective: Deep-dive the technical details for production and development use of API proxies and MITM frameworks.
Topics examined:
- mitmproxy addon API: all key hooks, flow objects, request/response modification
- TLS certificate interception mechanics: CA cert generation, dynamic cert issuance
- Certificate pinning: what it is, how mitmproxy handles it, bypass approaches
- HTTP/2 and gRPC proxying in mitmproxy
- Transparent proxy setup: TPROXY + mitmproxy, Docker networking
- proxy.py plugin API
- Envoy extension models: Lua, WASM, external processing
- Performance overhead: proxy latency at various throughputs
- WebSocket proxying across the tools
S2 Comprehensive Analysis: API Proxy / MITM Frameworks#
Research ID: 1.068 Pass: S2 — Comprehensive Analysis Date: 2026-02-17
1. mitmproxy Addon API — Deep Dive#
Hook Architecture#
mitmproxy uses an event-driven addon system. Addons are Python classes with methods named after hooks:
from mitmproxy import http, tls, websocket
from mitmproxy.connection import Server
class FullAddon:
# Called when a client request is received
def request(self, flow: http.HTTPFlow) -> None:
# Modify request before forwarding
flow.request.headers["X-Forwarded-By"] = "mitmproxy"
# Called when a server response is received
def response(self, flow: http.HTTPFlow) -> None:
# Modify response before sending to client
flow.response.headers["X-Intercepted"] = "true"
# Called before TLS handshake with upstream server
def tls_start_server(self, tls_handshake: tls.TlsData) -> None:
# Can inject custom TLS config, disable cert validation, etc.
tls_handshake.ssl_conn.set_tlsext_host_name(b"custom-sni")
# Called when a WebSocket message is received
def websocket_message(self, flow: websocket.WebSocketFlow) -> None:
msg = flow.messages[-1]
if msg.from_client:
msg.content = msg.content.replace(b"secret", b"REDACTED")
# Called on any error
def error(self, flow: http.HTTPFlow) -> None:
print(f"Error: {flow.error}")
addons = [FullAddon()]Flow Object Structure#
# http.HTTPFlow
flow.request.method # "GET", "POST", etc.
flow.request.url # Full URL
flow.request.headers # Headers dict (case-insensitive)
flow.request.content # Raw bytes
flow.request.text # Decoded text (per Content-Type charset)
flow.request.json() # Parse JSON body
flow.request.urlencoded_form # Parse form data
flow.response.status_code # 200, 404, etc.
flow.response.headers
flow.response.content # Raw bytes
flow.response.text
# Kill a flow (don't forward)
flow.kill()
# Set a custom response without contacting the server
flow.response = http.Response.make(
200,
b'{"mocked": true}',
{"Content-Type": "application/json"}
)Running Addons#
# Non-interactive (scripting)
mitmdump -s addon.py
# Interactive TUI with addon
mitmproxy -s addon.py
# Multiple addons
mitmdump -s addon1.py -s addon2.py
# Proxy port
mitmdump -s addon.py -p 8080Replay and Fuzzing#
# Save flows to file, replay later
# mitmdump -w flows.bin (record)
# mitmdump -r flows.bin (replay)
# Programmatic replay
from mitmproxy.tools import main
from mitmproxy import http
class FuzzAddon:
def request(self, flow: http.HTTPFlow):
# Modify a recorded flow before replay
if "api/v1/data" in flow.request.path:
flow.request.query["id"] = "' OR 1=1 --"2. TLS Certificate Interception#
How mitmproxy Handles HTTPS#
mitmproxy performs a “split TLS” connection:
Client ──TLS──▶ mitmproxy ──TLS──▶ Server
(fake cert) (real cert)Step-by-step:
- Client sends
CONNECT example.com:443 - mitmproxy responds
200 Connection established - Client initiates TLS to mitmproxy
- mitmproxy dynamically generates a certificate for
example.com, signed by its CA - Client verifies mitmproxy’s cert against the installed CA — passes if CA is trusted
- mitmproxy opens its own TLS connection to the real
example.com - mitmproxy can now read the plaintext traffic
CA cert setup:
# mitmproxy generates CA on first run
ls ~/.mitmproxy/
# mitmproxy-ca.pem (PEM format, install as trusted CA)
# mitmproxy-ca.p12 (PKCS12, for Windows/macOS keychain)
# Install on Linux system
sudo cp ~/.mitmproxy/mitmproxy-ca.pem /usr/local/share/ca-certificates/mitmproxy.crt
sudo update-ca-certificates
# Python requests (trust specific cert)
import requests
requests.get("https://example.com", verify="/path/to/mitmproxy-ca.pem")Certificate Pinning#
Certificate pinning is when a client hardcodes the expected certificate or public key, refusing any other — even if signed by a trusted CA. This breaks mitmproxy’s interception.
Where it’s used: Mobile apps (especially banking/payment), some desktop apps, IoT firmware.
Bypass approaches:
- android-unpinner (official mitmproxy tool): Automatically repackages an APK to disable certificate pinning.
pip install android-unpinner && android-unpinner app.apk. Handles common pinning implementations without manual decompilation. - Root the device + use Frida to hook the SSL verification function:
frida -U -l ssl_bypass.js com.target.app - Repack the APK manually: Decompile, remove pinning code, recompile
- Magisk + MagiskTrustUserCerts: On Android, make user CAs trusted as system CAs (bypasses some pinning)
mitmproxy’s --ssl-insecure: Skips certificate validation on the mitmproxy→server side only. Useful when the server has an invalid cert.
HSTS Implications#
HSTS (HTTP Strict Transport Security) tells the browser to always use HTTPS for a domain and never accept a different cert. In a controlled environment (testing your own apps), HSTS is not a problem. For intercepting third-party sites in a browser, HSTS-preloaded domains (google.com, etc.) cannot be intercepted via a proxy regardless of CA trust.
3. HTTP/2 and gRPC Proxying#
mitmproxy HTTP/2 and HTTP/3 Support#
mitmproxy supports HTTP/2 (enabled via --http2 flag or options.http2 = True). HTTP/2 is multiplexed over a single TLS connection — mitmproxy handles the framing transparently.
HTTP/3 (QUIC): Added in mitmproxy v11 (2024). HTTP/3 runs over UDP; mitmproxy intercepts it transparently.
mitmproxy --http2 # enable HTTP/2 support
# HTTP/3 is auto-detected when the client negotiates h3Limitations: HTTP/2 server push is not supported. HTTP/2 to HTTP/1.1 downgrade is the default behavior. gRPC cleartext (h2c, HTTP/2 prior knowledge without TLS) is not supported — encrypted gRPC (h2 over TLS) works fine.
gRPC over HTTP/2#
gRPC uses HTTP/2 with Protocol Buffers. mitmproxy can intercept gRPC traffic but sees it as binary HTTP/2 frames. To decode:
from mitmproxy import http
from google.protobuf import descriptor_pool, message_factory
import grpc
class GRPCAddon:
def response(self, flow: http.HTTPFlow):
if "application/grpc" in flow.response.headers.get("content-type", ""):
# Strip the 5-byte gRPC framing header
body = flow.response.content[5:]
# Decode with protobuf (requires .proto descriptor)
# msg = MyProtoMessage()
# msg.ParseFromString(body)Better approach: Use mitmproxy-grpc addon or Envoy’s gRPC-JSON transcoder filter (decodes gRPC automatically).
4. Transparent Proxy: TPROXY Deep Dive#
How TPROXY Works#
Normal proxying requires client configuration (HTTP_PROXY env or browser settings). TPROXY redirects packets at the network layer — the application is unaware.
Mechanism: The kernel intercepts packets destined for other hosts and delivers them to a listening socket. The receiving socket can retrieve the original destination via SO_ORIGINAL_DST or IP_TRANSPARENT.
iptables Setup (mitmproxy transparent mode)#
# Run as root or with CAP_NET_ADMIN
# 1. Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# 2. TPROXY redirect — use mangle table (NOT nat), preserves original destination IP
# The proxy retrieves it via getsockname() with IP_TRANSPARENT socket option
iptables -t mangle -A PREROUTING -p tcp --dport 80 \
-j TPROXY --tproxy-mark 0x1/0x1 --on-port 8080
iptables -t mangle -A PREROUTING -p tcp --dport 443 \
-j TPROXY --tproxy-mark 0x1/0x1 --on-port 8080
# 3. Route marked packets through loopback so the proxy can receive them
ip rule add fwmark 0x1 lookup 100
ip route add local default dev lo table 100
# 4. Exclude mitmproxy's own traffic (avoid loops)
iptables -t mangle -A PREROUTING -p tcp -m owner --uid-owner mitmproxyuser \
-j RETURNCritical distinction: Use the mangle table with -j TPROXY, not nat with -j REDIRECT. NAT REDIRECT rewrites the destination address and loses the original destination — the proxy can’t know where traffic was going. TPROXY preserves the original destination, allowing mitmproxy to open the real upstream connection.
Start mitmproxy in transparent mode:
mitmproxy --mode transparent --listen-port 8080Docker Network TPROXY#
For intercepting container traffic in a Docker network:
# Create a custom network
docker network create --subnet 172.20.0.0/16 proxy-net
# Add iptables rules for the Docker bridge (docker0 or custom)
iptables -t mangle -A PREROUTING -i br-<network-id> -p tcp --dport 80 \
-j TPROXY --tproxy-mark 0x1/0x1 --on-port 8080
iptables -t mangle -A PREROUTING -i br-<network-id> -p tcp --dport 443 \
-j TPROXY --tproxy-mark 0x1/0x1 --on-port 8080
ip rule add fwmark 0x1 lookup 100
ip route add local default dev lo table 100
# Run mitmproxy container in the same network
docker run --network host --cap-add NET_ADMIN \
mitmproxy/mitmproxy mitmdump --mode transparent -p 8080Simplified approach using docker-compose:
version: '3'
services:
mitm:
image: mitmproxy/mitmproxy
network_mode: host
cap_add:
- NET_ADMIN
command: mitmdump --mode transparent -p 8080 -s addon.py
target:
image: my-app
environment:
HTTP_PROXY: http://mitm:8080
HTTPS_PROXY: http://mitm:8080Note: Using HTTP_PROXY env is explicit proxy mode, not true transparent. For true transparent, the routing redirect approach is needed.
5. proxy.py Plugin API#
proxy.py is a lightweight alternative with a plugin system:
from proxy.http.proxy import HttpProxyBasePlugin
from proxy.http.parser import HttpParser
from proxy.common.utils import build_http_response
from proxy.http.codes import httpStatusCodes
class ModifyResponsePlugin(HttpProxyBasePlugin):
def before_upstream_connection(self, request: HttpParser):
# Return None to forward; return HttpParser to short-circuit
return None
def handle_client_request(self, request: HttpParser):
# Modify request headers
request.add_header(b"X-Custom", b"value")
return request
def handle_upstream_chunk(self, chunk: memoryview):
# Process response chunk
return chunkRun: proxy --plugin proxy.plugin.ModifyResponsePlugin
vs mitmproxy: proxy.py has lower latency overhead (async architecture) but the addon API is less ergonomic than mitmproxy’s flow-based model. mitmproxy gives you full request+response bodies assembled; proxy.py operates on chunks.
6. Envoy Extension Models#
Lua HTTP Filter#
Lua runs in-process in Envoy. Simple, low overhead, no compilation step.
-- envoy_filter.lua
function envoy_on_request(request_handle)
request_handle:headers():add("X-Custom", "from-envoy-lua")
end
function envoy_on_response(response_handle)
response_handle:headers():add("X-Intercepted", "true")
endEnvoy config:
http_filters:
- name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute
inline_code: |
function envoy_on_request(request_handle)
request_handle:headers():add("X-Custom", "lua-filter")
endLimitation: Lua filter cannot make async HTTP calls to external services. For that, use ext_proc.
External Processing (ext_proc) Filter#
ext_proc calls an external gRPC service for each request/response. The service can be written in any language including Python:
# Python gRPC ext_proc service
from envoy.service.ext_proc.v3 import external_processor_pb2_grpc
import grpc
class ExtProcService(external_processor_pb2_grpc.ExternalProcessorServicer):
def Process(self, request_iterator, context):
for processing_request in request_iterator:
# Inspect/modify headers, body
response = build_response(processing_request)
yield responseUse case: Calling ML models, databases, or rate-limiting services per request.
WASM Filter#
WASM filters are compiled binaries. Supported languages: Go (TinyGo), Rust, C++, AssemblyScript.
// Go WASM filter (TinyGo)
package main
import "github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
func main() {}
func init() {
proxywasm.SetVMContext(&vmContext{})
}
type httpContext struct {
proxywasm.DefaultHttpContext
contextID uint32
}
func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) proxywasm.Action {
proxywasm.AddHttpRequestHeader("x-wasm-filter", "active")
return proxywasm.ActionContinue
}7. Performance Overhead#
mitmproxy: Python-based processing adds significant latency per request — typically 5-50ms overhead depending on addon complexity. Not suitable for high-throughput production traffic. Designed for development/testing, not inline production proxying.
proxy.py: Lower overhead than mitmproxy (async I/O, less reflection). Benchmarks show ~2-10ms overhead. Suitable for low-traffic production scenarios.
Envoy: Written in C++. Overhead typically < 1ms. Designed for production at scale. Netflix, Lyft, Google use it in production service meshes.
Traefik: Go-based. Overhead typically 1-5ms. Good for medium-throughput reverse proxy scenarios.
Rule of thumb: mitmproxy for development/testing only. Envoy for production traffic interception at scale.
8. WebSocket Proxying#
| Tool | WebSocket Support | Notes |
|---|---|---|
| mitmproxy | ✅ v6+ | websocket_message hook; can modify WS frames |
| proxy.py | ✅ | Plugin hooks for WS frames |
| Envoy | ✅ | Transparent WebSocket proxying; no frame-level filter API |
| Traefik | ✅ | Transparent (no frame-level access) |
| nginx | ✅ (reverse proxy) | Requires Upgrade/Connection headers |
mitmproxy is the only tool with a Python API for frame-level WebSocket modification.
Sources#
- mitmproxy documentation
- mitmproxy addon API
- mitmproxy transparent proxy
- proxy.py documentation
- Envoy proxy documentation
- Envoy Lua HTTP filter
- Envoy external processing
- Traefik documentation
- iptables TPROXY
S2 Recommendation: Comprehensive Analysis#
Core Decision: What Are You Trying To Do?#
Debug/test your own API traffic → mitmproxy Python addon API, full request/response bodies, mocking, replay. 5-50ms overhead is fine for dev.
Intercept traffic without client config changes → mitmproxy (transparent) + iptables/TPROXY Requires root/NET_ADMIN capability. Installs at the network level.
Production traffic routing/modification → Envoy C++ performance, WASM/Lua/ext_proc extension models. Not for ad-hoc testing.
Reverse proxy with auto-discovery → Traefik Docker/K8s label-based config, automatic HTTPS. Not a MITM tool per se.
Python logic inside Envoy → ext_proc filter Write a Python gRPC service; Envoy calls it per request. Bridge between Python and C++ proxy.
WebSocket frame-level interception → mitmproxy only No other open-source Python tool exposes WebSocket frame hooks.
What To Avoid#
- mitmproxy in high-throughput production paths (Python overhead)
- Expecting TPROXY to work without root/NET_ADMIN
- Expecting mitmproxy to bypass certificate pinning automatically
S2 Synthesis: API Proxy / MITM Frameworks#
What S2 Confirmed from S1#
- mitmproxy’s addon API is Python-native and ergonomic: full request/response flow objects, not raw chunks
- TLS interception = “split TLS” with dynamic cert generation signed by a custom CA
- TPROXY is the Linux kernel mechanism for transparent proxy; iptables rules redirect traffic
- Envoy is production-grade C++ with
<1ms overhead; mitmproxy is 5-50ms Python
What S2 Added#
mitmproxy flow modification is powerful: flow.response = http.Response.make(...) completely replaces the server response. flow.kill() drops the request. These enable sophisticated testing and mock injection without any server changes.
Certificate pinning requires app-level bypass: mitmproxy’s CA substitution doesn’t work against cert-pinning. Bypass requires Frida (hooking SSL verification) or APK recompilation. For testing your own apps, disable pinning in debug builds.
HTTP/2 and gRPC work but need extra steps: mitmproxy proxies HTTP/2 transparently. gRPC bodies are binary protobuf — need the .proto schema or mitmproxy-grpc addon to decode. Envoy’s gRPC-JSON transcoder is better for production gRPC observability.
ext_proc enables Python + Envoy: Envoy’s external processing filter calls a Python gRPC service per request. This is the path to Python-based logic in a production Envoy deployment.
proxy.py is chunk-based vs flow-based: Lower overhead but less ergonomic. Good if you need a low-latency inline proxy; mitmproxy if you need full body access.
WebSocket frames accessible in mitmproxy: websocket_message hook gives access to individual frames — unique among these tools.
Recommended Slots#
| Use Case | Tool | Quality |
|---|---|---|
| Python HTTP/HTTPS interception/testing | mitmproxy | ✅ Production for dev/test |
| Lightweight Python proxy | proxy.py | ✅ When performance matters |
| Production service mesh proxy | Envoy | ✅ Production |
| Production reverse proxy | Traefik | ✅ Production |
| Transparent OS-level redirect | iptables/TPROXY | ✅ Linux standard |
| Python logic in Envoy | ext_proc gRPC service | ✅ Pattern |
S3: Need-Driven
S3 Approach: Need-Driven Discovery#
Objective: Work backward from real use cases to the correct tool choice.
Topics examined:
- API development testing: intercept and mock HTTP calls from a Python app
- Security testing / vulnerability research: OWASP fuzzing, auth bypass testing
- Traffic recording and replay: capture prod-like traffic for testing
- Container/microservice observability: intercept service-to-service traffic
- IoT / mobile device traffic analysis: intercept device traffic without app changes
- Rate limiting and circuit breaking: production traffic modification
- Constraint matrix: no root, no client config, serverless
S3 Library Comparison: By Need Matrix#
Decision Matrix#
| Need | mitmproxy | proxy.py | Envoy | Traefik | iptables/TPROXY |
|---|---|---|---|---|---|
| Python scripting API | ✅ Best | ✅ Good | ❌ | ❌ | N/A |
| Full request/response body access | ✅ | ⚠️ (chunks) | ✅ ext_proc | ❌ | N/A |
| No client config (transparent) | ✅ (needs root) | ✅ (needs root) | ✅ | ✅ | ✅ required |
| TLS interception | ✅ split TLS | ✅ | ✅ | ✅ | N/A |
| gRPC proxying | ✅ (binary) | ⚠️ | ✅ (native) | ✅ | N/A |
| WebSocket frame access | ✅ | ✅ | ❌ | ❌ | N/A |
| Production traffic path | ❌ (slow) | ⚠️ | ✅ | ✅ | N/A |
| Docker/K8s auto-discovery | ❌ | ❌ | ✅ (xDS) | ✅ | N/A |
| Traffic recording/replay | ✅ native | ❌ | ❌ | ❌ | N/A |
| Rate limiting | ❌ | ❌ | ✅ | ✅ | N/A |
| No root required | ✅ (explicit mode) | ✅ | ✅ | ✅ | ❌ |
Tool Persona Summary#
mitmproxy: The developer’s Swiss Army knife. Python scripts, full body access, recording, replay, interactive TUI. Not for production traffic paths.
proxy.py: mitmproxy’s lighter sibling. Good async performance. Plugin API less ergonomic but lower overhead. Suitable for lightweight CI/CD proxying.
Envoy: Production infrastructure proxy. C++ performance, rich extension model (Lua/WASM/ext_proc). Not a development tool — steep learning curve, YAML-heavy config.
Traefik: Production reverse proxy with killer Docker/K8s integration. Auto-discovers services via labels. Simpler than Envoy for most cases. Less flexible extension API.
iptables/TPROXY: Not a proxy itself — a Linux routing mechanism. Required for transparent proxy without client config. Paired with mitmproxy or any proxy daemon.
When to Layer Tools#
mitmproxy + iptables: Transparent interception in a test environment. Intercept all container traffic without configuring each container.
Envoy + ext_proc (Python gRPC service): Production proxy with Python logic. Envoy handles the C++ performance layer; Python gRPC service handles business logic per request.
Traefik + mitmproxy (chained): Traefik as production edge; mitmproxy in dev/test environment behind Traefik for debugging specific service calls.
S3 Recommendation: Need-Driven#
By Use Case#
API development and testing → mitmproxy Python addon API, mock injection, recording/replay. The right tool for the job.
Security testing / fuzzing → mitmproxy Request modification hooks, response inspection, upstream chaining to Burp Suite.
Transparent interception (no client config) → mitmproxy + iptables TPROXY Requires root/NET_ADMIN. Works at the network level.
Production traffic modification → Envoy Rate limiting, circuit breaking, observability. C++ performance.
Production reverse proxy → Traefik Docker/K8s auto-discovery, automatic HTTPS, simpler than Envoy.
Python logic in Envoy → ext_proc filter Write a Python gRPC service; call it from Envoy per request.
Certificate pinning bypass → Frida App-level hook. Outside the proxy layer entirely.
One-Line Rule#
For anything Python and development/testing: mitmproxy. For production traffic paths: Envoy or Traefik.
S3 Use Cases: API Proxy / MITM Frameworks#
Use Case 1: API Development — Mock and Intercept HTTP Calls#
Who: Developer testing a Python app that makes HTTP calls to a third-party API. Wants to intercept and mock responses without changing the app code.
Solution: mitmproxy addon:
# mock_addon.py
from mitmproxy import http
import json
MOCK_RESPONSES = {
"/api/v1/users": {"users": [{"id": 1, "name": "Test User"}]},
"/api/v1/status": {"status": "ok"},
}
class MockAPI:
def request(self, flow: http.HTTPFlow):
path = flow.request.path
if path in MOCK_RESPONSES:
flow.response = http.Response.make(
200,
json.dumps(MOCK_RESPONSES[path]).encode(),
{"Content-Type": "application/json"}
)
addons = [MockAPI()]mitmdump -s mock_addon.py -p 8080
# Run app with proxy
HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 python app.pyWhy this beats other approaches: No test doubles in application code. The app runs unmodified — only the network is intercepted.
Use Case 2: Security Testing — API Fuzzing and Auth Testing#
Who: Security researcher or developer doing OWASP-style testing.
Solution: mitmproxy for parameter fuzzing:
# fuzz_addon.py
from mitmproxy import http
import itertools
PAYLOADS = ["' OR 1=1 --", "<script>alert(1)</script>", "../../../etc/passwd"]
class SQLiFuzzer:
def __init__(self):
self.payload_iter = itertools.cycle(PAYLOADS)
def request(self, flow: http.HTTPFlow):
if flow.request.method == "POST" and "/api/" in flow.request.path:
# Inject payload into each form parameter
form = flow.request.urlencoded_form
for key in form.keys():
form[key] = next(self.payload_iter)
def response(self, flow: http.HTTPFlow):
# Flag suspicious responses
indicators = ["syntax error", "mysql", "ora-", "stack trace"]
body = (flow.response.text or "").lower()
if any(i in body for i in indicators):
print(f"[!] Potential injection: {flow.request.url}")
addons = [SQLiFuzzer()]Integration with Burp Suite: mitmproxy can chain to Burp — send intercepted flows to Burp for its active scanner. Use --upstream http://burp-host:8080.
Use Case 3: Traffic Recording and Replay#
Who: Developer wanting to capture real production-like traffic to use as test fixtures.
Record with mitmproxy:
# Record all traffic to a file
mitmdump -w recordings/session1.flows
# With filter (only record /api/ requests)
mitmdump -w recordings/session1.flows "~u /api/"Replay in CI/CD:
# Replay recorded flows (sends requests to original servers)
mitmdump -r recordings/session1.flows
# Replay with addon that modifies each replayed request
mitmdump -r recordings/session1.flows -s replay_modifier.pyPython: load and inspect recorded flows:
from mitmproxy import io
from mitmproxy.http import HTTPFlow
with open("recordings/session1.flows", "rb") as f:
reader = io.FlowReader(f)
for flow in reader.stream():
if isinstance(flow, HTTPFlow):
print(f"{flow.request.method} {flow.request.url}")
print(f" Status: {flow.response.status_code}")Use case: Record a manual session of using your web app, then use the recording as a regression test to ensure responses don’t change.
Use Case 4: Microservice Observability (Without App Changes)#
Who: Platform engineer wanting to observe all HTTP traffic between microservices in a Docker network.
Solution: mitmproxy sidecar + TPROXY:
# docker-compose.yml
version: '3'
services:
proxy:
image: mitmproxy/mitmproxy
network_mode: host
cap_add: [NET_ADMIN]
command: mitmdump --mode transparent -p 8080 -s observe.py
service-a:
build: ./service-a
environment:
HTTP_PROXY: http://proxy:8080
HTTPS_PROXY: http://proxy:8080observe.py (log all inter-service traffic):
from mitmproxy import http
import json, logging
logger = logging.getLogger(__name__)
class ObservabilityAddon:
def response(self, flow: http.HTTPFlow):
logger.info(json.dumps({
"method": flow.request.method,
"url": flow.request.url,
"status": flow.response.status_code,
"duration_ms": (flow.response.timestamp_end -
flow.request.timestamp_start) * 1000,
}))Production alternative: For production observability, use Envoy with a custom access log format or the ext_proc filter. Avoid mitmproxy in production traffic paths.
Use Case 5: IoT / Mobile Device Traffic Analysis#
Who: Developer reverse-engineering a mobile app’s API or debugging IoT device communication.
Setup:
- Run mitmproxy on a laptop/server
- Set the mobile device’s WiFi proxy to point to mitmproxy IP:8080
- Install mitmproxy CA cert on the device
- Browse/use the app — all traffic is intercepted
mitmweb --listen-host 0.0.0.0 --listen-port 8080
# Access web UI at http://localhost:8081Android certificate installation (Android 7+ requires system CA for app traffic):
- Root device + Magisk: install as system CA
- Or: compile app with
network_security_config.xmlallowing user CAs (debug builds)
For true transparent mode (no device config changes):
- Act as a WiFi router/gateway
- Apply iptables TPROXY rules on the gateway
- Device traffic is automatically intercepted
Certificate pinning: Most banking/payment apps pin their certs. Bypass with Frida:
frida -U -l ssl-bypass.js com.targetbank.app
# ssl-bypass.js hooks javax.net.ssl.TrustManager to accept any certUse Case 6: Production Rate Limiting and Circuit Breaking#
Who: Platform engineer adding rate limiting to a legacy service that doesn’t support it natively.
Solution: Traefik middleware (production):
# traefik dynamic config
http:
middlewares:
rate-limit:
rateLimit:
average: 100
period: 1s
burst: 50
routers:
my-service:
rule: "Host(`api.example.com`)"
middlewares: [rate-limit]
service: my-serviceEnvoy rate limiting filter:
http_filters:
- name: envoy.filters.http.ratelimit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
domain: my-service
rate_limit_service:
grpc_service:
envoy_grpc:
cluster_name: rate_limit_clusterNot mitmproxy: Rate limiting in production traffic paths requires Envoy or Traefik — not Python-based proxies.
Use Case 7: Testing Without Root (Explicit Proxy Mode)#
Constraint: No root/NET_ADMIN capability. Can set HTTP_PROXY env variable but can’t redirect at OS level.
Solution: Explicit proxy + per-process configuration:
# Start mitmproxy on localhost
mitmdump -s addon.py -p 8080
# Configure Python requests
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
# Or in Python
import requests
proxies = {"http": "http://localhost:8080", "https": "http://localhost:8080"}
resp = requests.get("https://api.example.com", proxies=proxies, verify=False)Limitation: Only processes you control and configure will use the proxy. Background processes, system daemons, or apps with hardcoded proxies won’t.
For testing microservices: Pass HTTP_PROXY to Docker containers at runtime:
docker run -e HTTP_PROXY=http://host.docker.internal:8080 my-serviceS4: Strategic
S4 Strategic Analysis: API Proxy / MITM Frameworks#
Research ID: 1.068 Pass: S4 — Strategic Analysis Date: 2026-02-17
1. Maintenance Trajectory#
mitmproxy#
Maintainers: Core team of ~5 contributors. Maximiliano Siles, Aldo Cortesi, Thomas Kriechbaumer and others. Not backed by a company.
Activity: Active. v11.x (2025). Regular releases.
Financial model: Donations + sponsor contributions. No commercial backing.
Risk: Small team, no corporate backing. If key contributors move on, development could stall. However, the tool is popular enough (38K stars) that community contributions are strong.
Protocol coverage: Actively tracking HTTP/2, HTTP/3 (QUIC) support. WebSocket support added v6. gRPC passthrough works.
10-year confidence: MEDIUM-HIGH — niche enough to have dedicated maintainers, popular enough to have community contributions.
Envoy#
Maintainers: CNCF (Cloud Native Computing Foundation) graduated project. Major contributors: Google, Lyft, Microsoft, Amazon.
Activity: Extremely active. Daily commits. ~1,000 contributors.
Financial model: Corporate-sponsored OSS. Google/Amazon/Microsoft all use Envoy in production at massive scale.
Risk: Essentially none for production use. Enterprise-grade maintenance.
10-year confidence: VERY HIGH — critical infrastructure for major cloud providers.
Traefik#
Maintainers: Traefik Labs (commercial company). Traefik CE (community edition) is MIT licensed; Traefik Hub adds enterprise features.
Risk: Commercial company could pivot strategy. CE has historically been well-maintained. Traefik Labs was acquired in 2024 — watch for strategic changes.
10-year confidence: HIGH — but watch post-acquisition direction.
proxy.py#
Maintainers: Individual (Abhinav Singh). Limited contributors.
10-year confidence: LOW-MEDIUM — individual project, lower bus factor than mitmproxy.
2. Emerging: eBPF-Based Proxying#
eBPF (extended Berkeley Packet Filter) is a Linux kernel technology that allows running sandboxed programs in the kernel without kernel module changes. Tools like Cilium use eBPF for network proxying at L3/L4 — and increasingly at L7.
Cilium: eBPF-based networking for Kubernetes. Can do transparent HTTP proxying at the kernel level with ~microsecond overhead (much lower than userspace proxies like Envoy).
Implication: eBPF-based proxies may eventually replace Envoy sidecars for high-performance L7 interception. Cilium can already do HTTP-level policy enforcement via eBPF.
Timeline: eBPF L7 proxying is production-ready in Kubernetes with Cilium but not yet as configurable as Envoy. Envoy remains the standard for complex L7 logic (custom filters, ext_proc). Watch eBPF as a 5-year horizon replacement for sidecar proxy overhead.
3. Lock-in Analysis#
mitmproxy addons: Addons are pure Python. If mitmproxy is replaced, the business logic (mock responses, fuzzing, recording) can be migrated to proxy.py or another tool. Medium switching cost.
Envoy config (YAML + xDS): Envoy’s configuration is proprietary YAML with xDS API. Migrating to another proxy means rewriting all filter configs. High lock-in — but Envoy is so standard it’s worth the lock-in.
Traefik config: Dynamic config is YAML/TOML. Simpler than Envoy, but still tool-specific. Migrating from Traefik to Envoy is medium effort.
iptables/TPROXY: Pure Linux kernel. Zero lock-in — it’s a syscall interface.
4. Strategic Summary#
| Tool | 5-Year Outlook | Lock-in | Best Strategic Bet |
|---|---|---|---|
| mitmproxy | ✅ Active | Low | Dev/test interception |
| Envoy | ✅ CNCF standard | Medium | Production L7 proxy |
| Traefik | ✅ Active | Low-Medium | Production reverse proxy |
| proxy.py | ⚠️ Individual | Low | Lightweight only |
| eBPF/Cilium | 📈 Rising | Low | Watch for 2027+ |
The safe bet: mitmproxy for development, Envoy for production. These tools serve different purposes — there’s no single answer.
S4 Approach: Strategic Analysis#
Objective: Assess long-term viability, maintenance health, and strategic risks.
Topics examined:
- mitmproxy maintenance trajectory and funding
- Envoy governance and CNCF backing
- Traefik commercial vs open source trajectory
- Emerging alternatives: eBPF-based proxying
- Lock-in analysis for each tool
- Final recommendations
S4 Recommendation: Strategic Analysis#
Final Library Slots#
| Use Case | Tool | Strategic Confidence |
|---|---|---|
| Python MITM / dev testing | mitmproxy | ⭐⭐⭐⭐ Active, small team |
| Production L7 service proxy | Envoy | ⭐⭐⭐⭐⭐ CNCF standard |
| Production reverse proxy | Traefik | ⭐⭐⭐⭐ Watch post-acquisition |
| Lightweight Python proxy | proxy.py | ⭐⭐⭐ Individual project |
| Transparent OS redirect | iptables/TPROXY | ⭐⭐⭐⭐⭐ Linux kernel (permanent) |
Long-Term Outlook#
mitmproxy and Envoy serve fundamentally different purposes — they’re not competing. mitmproxy is a developer tool; Envoy is infrastructure. Both will remain relevant.
eBPF proxying is the 5-year trend to watch — it will reduce the need for Envoy sidecars in Kubernetes environments by handling L7 in the kernel itself.
Strategic Viability: API Proxy / MITM Frameworks#
Long-Term Slots#
| Tool | 2-Year | 5-Year | Role |
|---|---|---|---|
| mitmproxy | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Python dev/test proxy |
| Envoy | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | Production service proxy |
| Traefik | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Production reverse proxy |
| proxy.py | ⭐⭐⭐ | ⭐⭐⭐ | Lightweight/niche |
| eBPF/Cilium | ⭐⭐⭐ | ⭐⭐⭐⭐ | Future kernel-level proxy |
What to Build On#
Build on mitmproxy for: Python-scriptable interception, security testing, API mocking.
Build on Envoy for: Production service mesh, high-performance L7 filtering, gRPC.
Build on Traefik for: Docker/K8s edge proxy, automatic HTTPS, simple routing rules.
Watch eBPF/Cilium for: High-performance transparent proxying in Kubernetes (2027+).