RiccardoCataldi/claude_sniff

0

stars

1

commits

Python

primary language

Sep 4, 2026

updated

README

claude-sniff

Loopback MITM for Claude Code on Amazon Bedrock: sniff invokes, hold/edit the JSON, Forward (SigV4 re-sign) or Drop. One listener, one UI, no run wrapper.

This is not ANTHROPIC_BASE_URL=localhost. Claude Code on Bedrock does not speak that.

Proxy and Intercept start off and are not persisted.

Sessions

Usage

Edited hold, then Forward or Drop:

Proxy intercept

Prerequisites

  • Python 3.12+ and uv
  • Claude Code actually hitting Bedrock Runtime (CLAUDE_CODE_USE_BEDROCK=1, same region/profile as a working claude session)
  • AWS credentials in the process that runs main.py (AWS_PROFILE, SSO, or the default chain). Forwarding an edited body also needs InvokeModel on those same models (--aws-profile / AWS_PROFILE / SSO).

Quick start

uv sync
uv run python main.py --aws-profile your-profile   # optional; same chain as AWS_PROFILE

Listener: http://127.0.0.1:9090. UI: http://127.0.0.1:8765. First run writes the mitmproxy CA to ~/.mitmproxy/mitmproxy-ca-cert.pem.

UI tabs: Sessions, Usage, Proxy, Info. Proxy/Intercept are in the header (Intercept stays off until Proxy is on). Default view is Sessions.

1. Pin every new Claude Code process (it does not inherit exports from another shell):

export HTTP_PROXY=http://127.0.0.1:9090
export HTTPS_PROXY=http://127.0.0.1:9090
claude

With Proxy off, HTTPS is tunneled (Bedrock’s real cert, no CA). Usage still reads ~/.claude/projects.

2. Sniff: in the UI, turn Proxy on. Then, in the same shell as claude (or copy from the Info page):

export NODE_EXTRA_CA_CERTS="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
export SSL_CERT_FILE="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
export REQUESTS_CA_BUNDLE="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
export AWS_CA_BUNDLE="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"

Restart claude after the CA exports. Send a message. A session with x-claude-code-session-id appears under Sessions (and on the Proxy page while live). Rows land in logs/<client>/<session-id>.jsonl. Empty Sessions with Proxy off is expected; costs still come from ~/.claude/projects.

3. Intercept: turn Intercept on in the header (disabled until Proxy is on). Each Bedrock Runtime invoke / invoke-with-response-stream with x-claude-code-session-id is held. Edit the head JSON, then Forward or Drop.

  • Untouched JSON → resumed as the original (no re-sign).
  • Edited JSON → re-signed SigV4 from this process’s AWS chain (--aws-profile / AWS_PROFILE / SSO).
  • Drop → client-visible error, JSONL error row, no Bedrock call.
  • Global FIFO; only the head is editable. Turning Intercept or Proxy off flushes the queue as the original.

Trust the CA only while Proxy is on.

Costs

EU regional on-demand (eu-central-1) in the sidebar and per request. Family from model-name keywords, or from account-scoped application-inference-profile ids (this repo ships none):

export CLAUDE_PROXY_INFERENCE_PROFILES='{"yourId":"sonnet-4.6"}'

or a gitignored inference-profiles.json. Journals: ~/.claude/projects (--claude-projects-dir). Same UUID in logs/ and the journal is shown once (MITM dollars win). Direct rows are cost-only, no chat. Unknown model/profile → $0. Pricing is read-time; logs are not rewritten with costUSD.

Flags

FlagDefault
--port9090
--ui-port8765
--no-uiUI on
--logs-dirlogs/
--claude-projects-dir~/.claude/projects
--aws-profileprocess default chain
uv run python main.py ui          # UI only, no MITM

logs/ is gitignored. JSONL strips Authorization and x-amz-security-token; bodies (prompts, system) are stored as-is.

UI is served from ui/dist. Hot reload: keep main.py running, cd ui && bun run dev. Rebuild with cd ui && bun install && bun run build when shipping UI changes.

If nothing shows up

  • New claude after HTTP(S)_PROXY (and CA, if Proxy is on).
  • TLS errors with Proxy on → CA exports missing or an old process without them.
  • $0 → unknown model/profile; map inference-profile ids.
  • Intercept never holds → not a Bedrock invoke, or no x-claude-code-session-id.

What it does not do

  • Not a reverse proxy on ANTHROPIC_BASE_URL
  • Does not mask request bodies
  • Does not intercept or edit Bedrock responses
  • Does not persist Proxy/Intercept toggles
  • Does not ship request overlays or sample jailbreaks

Contributors

RiccardoCataldi/claude_sniff

0

stars

1

commits

Python

primary language

Sep 4, 2026

updated

README

claude-sniff

Loopback MITM for Claude Code on Amazon Bedrock: sniff invokes, hold/edit the JSON, Forward (SigV4 re-sign) or Drop. One listener, one UI, no run wrapper.

This is not ANTHROPIC_BASE_URL=localhost. Claude Code on Bedrock does not speak that.

Proxy and Intercept start off and are not persisted.

Sessions

Usage

Edited hold, then Forward or Drop:

Proxy intercept

Prerequisites

  • Python 3.12+ and uv
  • Claude Code actually hitting Bedrock Runtime (CLAUDE_CODE_USE_BEDROCK=1, same region/profile as a working claude session)
  • AWS credentials in the process that runs main.py (AWS_PROFILE, SSO, or the default chain). Forwarding an edited body also needs InvokeModel on those same models (--aws-profile / AWS_PROFILE / SSO).

Quick start

uv sync
uv run python main.py --aws-profile your-profile   # optional; same chain as AWS_PROFILE

Listener: http://127.0.0.1:9090. UI: http://127.0.0.1:8765. First run writes the mitmproxy CA to ~/.mitmproxy/mitmproxy-ca-cert.pem.

UI tabs: Sessions, Usage, Proxy, Info. Proxy/Intercept are in the header (Intercept stays off until Proxy is on). Default view is Sessions.

1. Pin every new Claude Code process (it does not inherit exports from another shell):

export HTTP_PROXY=http://127.0.0.1:9090
export HTTPS_PROXY=http://127.0.0.1:9090
claude

With Proxy off, HTTPS is tunneled (Bedrock’s real cert, no CA). Usage still reads ~/.claude/projects.

2. Sniff: in the UI, turn Proxy on. Then, in the same shell as claude (or copy from the Info page):

export NODE_EXTRA_CA_CERTS="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
export SSL_CERT_FILE="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
export REQUESTS_CA_BUNDLE="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
export AWS_CA_BUNDLE="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"

Restart claude after the CA exports. Send a message. A session with x-claude-code-session-id appears under Sessions (and on the Proxy page while live). Rows land in logs/<client>/<session-id>.jsonl. Empty Sessions with Proxy off is expected; costs still come from ~/.claude/projects.

3. Intercept: turn Intercept on in the header (disabled until Proxy is on). Each Bedrock Runtime invoke / invoke-with-response-stream with x-claude-code-session-id is held. Edit the head JSON, then Forward or Drop.

  • Untouched JSON → resumed as the original (no re-sign).
  • Edited JSON → re-signed SigV4 from this process’s AWS chain (--aws-profile / AWS_PROFILE / SSO).
  • Drop → client-visible error, JSONL error row, no Bedrock call.
  • Global FIFO; only the head is editable. Turning Intercept or Proxy off flushes the queue as the original.

Trust the CA only while Proxy is on.

Costs

EU regional on-demand (eu-central-1) in the sidebar and per request. Family from model-name keywords, or from account-scoped application-inference-profile ids (this repo ships none):

export CLAUDE_PROXY_INFERENCE_PROFILES='{"yourId":"sonnet-4.6"}'

or a gitignored inference-profiles.json. Journals: ~/.claude/projects (--claude-projects-dir). Same UUID in logs/ and the journal is shown once (MITM dollars win). Direct rows are cost-only, no chat. Unknown model/profile → $0. Pricing is read-time; logs are not rewritten with costUSD.

Flags

FlagDefault
--port9090
--ui-port8765
--no-uiUI on
--logs-dirlogs/
--claude-projects-dir~/.claude/projects
--aws-profileprocess default chain
uv run python main.py ui          # UI only, no MITM

logs/ is gitignored. JSONL strips Authorization and x-amz-security-token; bodies (prompts, system) are stored as-is.

UI is served from ui/dist. Hot reload: keep main.py running, cd ui && bun run dev. Rebuild with cd ui && bun install && bun run build when shipping UI changes.

If nothing shows up

  • New claude after HTTP(S)_PROXY (and CA, if Proxy is on).
  • TLS errors with Proxy on → CA exports missing or an old process without them.
  • $0 → unknown model/profile; map inference-profile ids.
  • Intercept never holds → not a Bedrock invoke, or no x-claude-code-session-id.

What it does not do

  • Not a reverse proxy on ANTHROPIC_BASE_URL
  • Does not mask request bodies
  • Does not intercept or edit Bedrock responses
  • Does not persist Proxy/Intercept toggles
  • Does not ship request overlays or sample jailbreaks

Contributors

Languages

Python

60.8%

TypeScript

30.7%

CSS

8.4%