Files
zerogravity/docs/mitm-interception-status.md
Nikketryhard 4e4d8e9474 chore: code cleanup and documentation overhaul
- Remove debug header dump from MITM proxy (was temp debugging code)
- Suppress dead_code warnings for intentional OpenAI compat fields
- Rewrite README with styled mermaid architecture diagrams, full
  feature listing, usage examples, and CLI reference
- Update endpoint-gap-analysis: images implemented, audio only stretch
- Update mitm-interception-status: add request modification and error
  capture components
- Update standalone-ls-todo: add new endpoints to test results
- Zero compiler warnings
2026-02-15 18:27:53 -06:00

5.9 KiB

MITM Traffic Interception — Status

Status: FULLY WORKING (Standalone Mode)

MITM interception is operational for the standalone LS. The proxy intercepts, decrypts, and parses all LLM API traffic with per-model token usage capture.

How It Works

Client → Proxy (8741) → Standalone LS (as antigravity-ls user)
                           ↓ (port 443 traffic)
                        iptables REDIRECT (UID-scoped)
                           ↓
                        MITM Proxy (8742)
                           ↓ (TLS decrypt + parse SSE)
                        Google API (daily-cloudcode-pa.googleapis.com)

Components

  1. UID-scoped iptables (scripts/mitm-redirect.sh)

    • Creates antigravity-ls system user
    • iptables rule: redirect UID's port-443 → MITM port
    • Only the standalone LS is affected — no side effects on other software
  2. Combined CA bundle (src/standalone.rs)

    • Go's SSL_CERT_FILE replaces (not appends) the system trust store
    • Proxy concatenates system CAs + MITM CA → /tmp/antigravity-mitm-combined-ca.pem
    • Set as SSL_CERT_FILE on the standalone LS process
  3. sudo -u spawning (src/standalone.rs)

    • If antigravity-ls user exists, LS is spawned via sudo -n -u antigravity-ls
    • Env vars passed via /usr/bin/env KEY=VALUE args
    • Falls back to current user if the dedicated user doesn't exist
  4. Google SSE parser (src/mitm/intercept.rs)

    • Parses data: {"response": {"usageMetadata": {...}}} events
    • Extracts promptTokenCount, candidatesTokenCount, thoughtsTokenCount
    • Handles both Google and Anthropic SSE formats
  5. Transparent proxy (src/mitm/proxy.rs)

    • Detects iptables-redirected connections via TLS ClientHello SNI
    • Terminates TLS with dynamically generated certs
    • Forwards HTTP/1.1 requests upstream with real DNS resolution (dig @8.8.8.8)
    • Chunked response detection for fast completion
  6. Request modification (src/mitm/modify.rs)

    • Strips LS system instructions down to <identity> block only
    • Removes stale conversation history (keeps only last user message)
    • Injects client tools, tool configs, generation params
    • Injects images as inlineData (base64) into user message parts
    • Injects tool results as functionResponse parts
    • Enables Google Search grounding when requested
    • Updates Content-Length header after body modification
  7. Upstream error capture (src/mitm/store.rs)

    • Captures Google API error responses (HTTP 400, 429, 500, etc.)
    • Parses error JSON for message and status fields
    • Stores in MitmStore for immediate forwarding to client
    • Prevents request hangs on upstream failures

What We Tried (Historical)

1. Extension Patch — detectAndUseProxy Still Active

Patches detectAndUseProxy=1 in the extension JS. Makes auxiliary traffic (Unleash, etc.) honor HTTPS_PROXY. Harmless, still applied.

2. MITM Wrapper (mitm-wrapper.sh) ⚠️ Superseded

Sets env vars on the main LS process. Works for routing but the main LS's LLM client ignores HTTPS_PROXY. Superseded by standalone mode.

3. iptables REDIRECT (All Traffic) Abandoned

Redirected ALL port-443 traffic. Caused redirect loops, broke other HTTPS traffic. Replaced by UID-scoped redirect.

4. DNS Redirect (/etc/hosts) Abandoned

Same TLS trust issue as #3. Unnecessary with UID-scoped iptables.

5. Standalone LS + UID-scoped iptables WORKING

Current solution. Full MITM interception with zero side effects.

The Original Blocker (SOLVED)

The LS's Go LLM HTTP client uses a custom tls.Config that does NOT read from SSL_CERT_FILE or the system CA store.

This turned out to be wrong. The Go client DOES honor SSL_CERT_FILE when:

  • The env var is set BEFORE the process starts (not injected later)
  • The value contains a combined bundle (system CAs + custom CA)
  • SSL_CERT_DIR is set to /dev/null to force exclusive use of SSL_CERT_FILE

The standalone LS gives us full control over the process environment at spawn time, which is why this approach works while the wrapper approach didn't.

Technical Details

API Endpoint

POST https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse

SSE Response Format

data: {"response": {"candidates": [{"content": {"role": "model", "parts": [{"text": "..."}]}}],
       "usageMetadata": {"promptTokenCount": 1514, "candidatesTokenCount": 25,
                         "totalTokenCount": 1539, "thoughtsTokenCount": 52},
       "modelVersion": "gemini-3-flash"}, "traceId": "...", "metadata": {}}

Last event includes "finishReason": "STOP" in the candidate.

Other Intercepted Endpoints

Endpoint Type Content
fetchUserInfo Protobuf User info
loadCodeAssist Protobuf Extension config
fetchAvailableModels Protobuf Model catalog
webDocsOptions Protobuf Docs config
streamGenerateContent SSE/JSON LLM responses
recordCodeAssistMetrics Protobuf Telemetry
recordTrajectoryAnalytics Protobuf Telemetry

Model IDs

Placeholder Model
MODEL_PLACEHOLDER_M18 Gemini 3 Flash
MODEL_PLACEHOLDER_M8 Gemini 3 Pro (High)
MODEL_PLACEHOLDER_M7 Gemini 3 Pro (Low)
MODEL_PLACEHOLDER_M26 Claude Opus 4.6
MODEL_PLACEHOLDER_M12 Claude Opus 4.5

Setup

# One-time setup (creates user + iptables rule)
sudo ./scripts/mitm-redirect.sh install

# Run proxy (standalone + MITM are default)
RUST_LOG=info ./target/release/antigravity-proxy

# Check usage
curl -s http://localhost:8741/v1/usage | jq .

Cleanup

# Remove iptables rule + user
sudo ./scripts/mitm-redirect.sh uninstall