cctbp.com | Tom Stacy, CISSP®
Before you can find the seam in an authentication flow, you need to see the flow clearly. That means a lab that gives you deterministic results every time — no shared browser state, no ambient noise, no accidental leakage to live environments. This post is the foundation setup for everything else in this series.
The architecture here is deliberately minimal: Docker for containerization, mitmproxy for interception, Firefox Multi-Account Containers for browser-level session isolation. FOSS throughout, nothing exotic. The payoff is a lab you can tear down, wipe, and rebuild from scratch in under five minutes.
The Setup
The core problem with ad hoc interception labs is state contamination. Your regular browser profile bleeds cookies into test sessions. Your OS-level proxy config leaks across unrelated tabs. A hand-configured VM breaks after an update and takes an afternoon to restore. None of that is acceptable when you’re trying to reproduce an auth-flow edge case reliably.
The architecture draws a hard boundary around the testing environment at two levels:
- Network level: all traffic routes through a proxy listener before it reaches any target. No path to production systems from your main IP.
- State level: each test role runs in an isolated browser container with its own cookie jar, cache, and local storage.
The proxy sits in the middle. The isolated browser talks through it. The target — a local, containerized vulnerable app — sits at the end. Nothing touches live infrastructure.
[ Isolated Browser / Container ]
│
▼ (Proxy on Port 8080)
[ Intercepting Proxy ] <-- mitmweb / mitmproxy / mitmdump
│
▼
[ Target Server ]
The Seam
The seam in most ad hoc lab setups is the boundary between your research environment and everything else on your machine. The failure modes are predictable: a test session’s cookies end up in your regular browser, a proxy config change affects traffic you didn’t intend to intercept, or a log file captures a token that survives a lab teardown.
Docker eliminates the infrastructure drift problem. Browser containers eliminate the session bleed problem. Explicit proxy-per-container configuration keeps the intercept surface bounded.
The second seam is signal-to-noise. Auth flows are already multi-step redirect chains. If your proxy is catching browser telemetry, analytics pings, and system update checks alongside the flows you care about, you’ll miss things. Noise reduction is not optional.
Reproducing It
Prerequisites
- Debian-based host (clean Debian install or Kali)
- Docker installed
- Firefox with the Multi-Account Containers extension
- mitmproxy installed (
pip install mitmproxy)
Step 1: Inject the Proxy’s Root CA
mitmproxy generates its CA on first run at ~/.mitmproxy/mitmproxy-ca-cert.pem. Run it once to generate, then install:
# Run mitmproxy once to generate the CA, then Ctrl-C
mitmweb
# Copy the CA cert to the Debian trust store
sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem \
/usr/local/share/ca-certificates/mitmproxy-ca-cert.crt
# Update the trust store
sudo update-ca-certificates
Verify it registered:
grep -r "mitmproxy" /etc/ssl/certs/
Step 2: Write an Auth Logger Addon
mitmproxy’s Python addon API makes deterministic traffic manipulation trivial. This addon logs intercepted authorization tokens at the request hook — read-only by design. The same hook is where you’d add mutation logic for active token rewriting:
import logging
from mitmproxy import http
class AuthLogger:
def request(self, flow: http.HTTPFlow) -> None:
if "Authorization" in flow.request.headers:
token = flow.request.headers["Authorization"]
# Log only a prefix — never write full tokens to disk
logging.info(f"[AUTH LOG] Intercepted token: {token[:20]}...")
addons = [
AuthLogger()
]
Save as auth_logger.py.
Step 3: Run the Proxy
For interactive auth-flow analysis, mitmweb is the right interface. It renders the full redirect chain in a clickable flow list, toggles intercept mode without leaving the browser, and lets you edit and replay any request in place.
mitmweb -s auth_logger.py
Proxy listener: 127.0.0.1:8080. The web UI opens automatically in your default browser.
When you’re ready to automate the same checks headlessly — batch runs, CI integration, scripted regression — point the same addon at mitmdump:
mitmdump -p 8080 -s auth_logger.py
Same core engine, no UI overhead. The three interfaces (mitmproxy TUI, mitmweb, mitmdump) share an identical addon API, so addons are portable across all three without modification.
Step 4: Silence Background Noise
mitmproxy filter expressions use the ~u operator to match against URL patterns via regex. Add these to your startup config or as intercept filters in mitmweb to drop traffic you don’t care about:
~u "telemetry|analytics|update|safebrowsing|ocsp"
Set them as ignore patterns so matched flows are passed through without appearing in the flow list:
mitmweb -s auth_logger.py \
--ignore-hosts ".*telemetry.*|.*analytics.*|.*safebrowsing.*"
The result is a clean flow list showing only the auth-relevant traffic.
Step 5: Configure Browser Session Containers
Firefox Multi-Account Containers gives you entirely independent cookie jars, cache domains, and local storage per container. For auth research, this means you can run Admin and User roles side-by-side in separate tabs without any state bleed between them.
Per-container proxy configuration (the key capability) lives under each container’s Advanced Proxy Settings. Route the container directly to 127.0.0.1:8080:
- Open Firefox Multi-Account Containers → Edit the container → Advanced Proxy Settings
- Set proxy:
127.0.0.1, port8080 - Assign one container per test role: Admin, User, Attacker
Tab A (Admin container) and Tab B (User container) are now independent authentication contexts, both feeding through the same mitmproxy listener. You’ll see each flow labeled with its origin if you tag them in the addon.
Step 6: Stand Up a Local Target
Rather than pointing your proxy at live production targets, spin up a local vulnerable app. A minimal containerized token-validation service that accepts alg:none JWTs gives you an immediate, risk-free environment to test JWT vulnerabilities, signature bypasses, and session-state mechanics without touching anything real.
Example docker-compose.yml for a Flask-based target:
version: "3.8"
services:
target:
build: ./target
ports:
- "8000:8000"
environment:
- ACCEPT_ALG_NONE=true
The entire stack — proxy, addon, vulnerable target — is now declarative. docker compose up puts the target online. mitmweb -s auth_logger.py puts the proxy in the path. Teardown is docker compose down and pkill mitmweb. From scratch to running lab in under five minutes.
Defender Perspective
This lab architecture mirrors what a well-instrumented production environment should look like from a logging perspective. Every request that passes through mitmproxy is a structured, inspectable event — the same property you want from your production proxy or WAF logs.
What this setup makes visible:
- Full redirect chains in sequence. OAuth and SAML flows involve multiple 302s across different origins. The mitmweb flow list renders them in order with timing. If your production logs don’t give you this view, you have a detection gap.
- Header-level token movement. The auth logger addon demonstrates exactly what to look for in production:
Authorizationheaders on requests that shouldn’t carry them, or tokens appearing on endpoints outside their expected scope. - Cross-session state. Running Admin and User containers side-by-side through the same proxy is how you catch horizontal privilege escalation bugs during testing — and it’s the same signal you’d look for in production logs when two accounts share unexpected session state.
For blue teamers evaluating their own logging fidelity: if you can’t reconstruct a full OAuth authorization code flow from your proxy logs — authorization request, redirect, code exchange, token issuance — your log coverage is insufficient for detecting authorization code interception.
Takeaway
For red teamers: The lab is infrastructure, not a technique. Set it up once properly and every subsequent scenario runs against a known baseline. The containerized teardown-and-rebuild property is the critical one — it means you can verify a finding from scratch, on demand, without any “it worked yesterday” ambiguity. The same architecture scales to more complex multi-IDP flows without modification; you add containers, not complexity.
For defenders: The noise reduction and session isolation techniques here are directly applicable to your production monitoring setup. If your WAF or reverse proxy isn’t filtering auth-relevant traffic from background noise before it hits your SIEM, your detection rules are working harder than they need to. The signal you want is clean before it reaches detection logic, not after.
🚀 Looking to scale past local setups? If you’re testing distributed authentication architectures and need an automated, cloud-hosted platform for authorized OAuth, SAML, and OIDC interception without the local infrastructure overhead, join the ShroudCloud waitlist.
Tom Stacy, CISSP®, is an authentication and identity security specialist. He writes at cctbp.com and is building ShroudCloud™, an engagement infrastructure for auth and session security.