mitmproxy (regular forward-proxy) + a Python addon that injects secrets pulled from
Bitwarden Secrets Manager (bws) into allowlisted outbound requests. Deny-by-default:
unlisted hosts get a 403. Secret values are never logged.
Portable how-it-works / connect-a-tool docs live in the
secrets-injection-brokerskill (~/.claude/skills/secrets-injection-broker/). This README is the machine-specific runbook.
Broker and the dev container both run rootless on podman-machine-default (default connection),
sharing a user-defined network broker-net:
- Host Claude Code →
localhost:8080(broker published-p 127.0.0.1:8080:8080). - dev container →
broker:8080(container-to-container overbroker-net; no host port, not LAN-exposed).
Engine-separation note: broker + dev share one engine, so a dev with the docker socket ON could
exec the broker and read BWS_ACCESS_TOKEN. The socket is OFF by default — keep it off while co-located.
(Co-location was chosen over a separate machine because cross-machine networking forced LAN/Tailscale/VPN exposure.)
Containerfile python:3.12-slim + bws 2.1.0 (sha-pinned) + mitmproxy + PyYAML
addon.py deny-by-default injection (header/bearer/basic/query, name->id map, TTL cache)
routes.yaml allowlist + injection config (secret = bws KEY NAME)
ca/ exported PUBLIC CA cert (gitignored)
.env* NOT used — token is a podman secret; BWS_SERVER_URL is a plain -e (EU region)
podman build -t broker:latest C:\projects\2026\10_broker
podman network create broker-net # once
# one-time: store the BWS token as a podman secret (byte-exact temp file; no Git-Bash stdin — MSYS corrupts it)
$t = "$env:TEMP\bwstok"; [IO.File]::WriteAllText($t, '<TOKEN>', (New-Object Text.UTF8Encoding($false)))
podman secret create BWS_ACCESS_TOKEN $t; Remove-Item $t -Force
# run: shared network + loopback publish + hardened
podman run -d --name broker --init --network broker-net `
-p 127.0.0.1:8080:8080 `
--secret BWS_ACCESS_TOKEN,type=env `
-e BWS_SERVER_URL=https://vault.bitwarden.eu ` # EU account; REQUIRED or bws -> invalid_client
-v broker-ca:/home/broker/.mitmproxy:U `
--read-only --tmpfs /tmp --tmpfs /home/broker/.config `
--cap-drop=ALL --security-opt=no-new-privileges `
--restart=on-failure:5 `
--memory=512m --memory-swap=512m --pids-limit=512 --ulimit core=0 `
broker:latest
# export the PUBLIC ca cert for clients to trust
podman cp broker:/home/broker/.mitmproxy/mitmproxy-ca-cert.pem C:\projects\2026\10_broker\ca\Changing routes = rebuild + recreate. routes.yaml is baked into the image and the rootfs is
--read-only, so podman cp into /app fails (500). Edit routes.yaml → podman build → recreate.
After any CA regen, reconnect host MCP servers (they load the CA at launch).
| host | inject | secret |
|---|---|---|
api.search.brave.com |
header X-Subscription-Token |
BRAVE_API_KEY |
api.mem0.ai |
header Authorization = Token {value} |
MEM0_API_KEY |
api.notion.com |
bearer | NOTION_TOKEN |
github.com |
basic (x-access-token) — git push/pull (write-capable) |
GITHUB_TOKEN |
brave-search, mem0, notion launch under Bun with a placeholder token + broker proxy + CA, e.g.:
(notion: bin/cli.mjs --transport stdio, env NOTION_TOKEN. brave: server-brave-search/dist/index.js, env BRAVE_API_KEY.)
Runtime gotcha: these servers honor HTTPS_PROXY only under Bun — the ~/.bun/bin/*.exe shims run
under Node, which ignores it (sends the placeholder → upstream auth error, no broker hit). Always launch
via bun.exe <dist/index.js>. curl.exe (Schannel) needs --ssl-no-revoke to honor --cacert.
Scoped per-server — Claude's own Anthropic/Max traffic is NOT proxied. github MCP currently runs direct
(mcp-server-github.exe, no token) — unbrokered; could be brokered via the github.com/api.github.com route + a Bun launch.
dev is on broker-net; broker CA at /home/dev/broker-ca.pem. Git scoped to github.com only:
git config --global http.https://github.com/.proxy http://broker:8080
git config --global http.https://github.com/.sslCAInfo /home/dev/broker-ca.pem
Broker injects Basic auth (PAT) → git push/pull works without the token in dev. Host stays on gh CLI.
curl.exe -x http://localhost:8080 --ssl-no-revoke --cacert C:\projects\2026\10_broker\ca\mitmproxy-ca-cert.pem `
-H "Accept: application/json" "https://api.search.brave.com/res/v1/web/search?q=test" # 200 (injected)
curl.exe -x http://localhost:8080 --ssl-no-revoke https://example.com/ # 403 (not allowlisted)routes.yamlsecrets are bws key names — must exist in the project or the broker won't start (fail-loud).- Secret fetches are TTL-cached (
BROKER_CACHE_TTL, default 300s). - Anthropic/model traffic must NOT be routed here (keeps Max-plan native).
:8080is unauthenticated but only reachable via host loopback + the internalbroker-net(no LAN). If exposure ever broadens, add Proxy-Authorization (esp. given the write-capablegithub.comroute).