Skip to content

feature: language-runtime HTTPS interception via Node/Python hooks #431

Description

@huang195

Background

AuthBridge's outbound forward proxy supports two paths today:

  • Plain HTTP outbound — full pipeline (ibac, mcp-parser, inference-parser, token-exchange) sees plaintext, can modify headers/body, can inject credentials.
  • HTTPS via CONNECT tunnel (✨ feat(forwardproxy): support HTTPS CONNECT as raw TCP passthrough #430) — destination policy on host:port only; bytes are end-to-end TLS between agent and origin, opaque to the proxy.

This leaves a gap: for agents that talk HTTPS to external APIs (which is most modern agents — openai, @anthropic-ai/sdk, etc.), AuthBridge can enforce destination policy but cannot inspect or modify request content. PR #430 explicitly notes: "Token-exchange for HTTPS targets — fundamentally not possible (the bytes are encrypted)."

The standard answer is TLS-bumping (MITM with a forged-cert proxy whose CA the agent trusts). This works but carries significant cost: per-pod CA distribution, cert-pinning collisions, ECH migration risk, breakage of provider-side client-cert auth, and a high-value CA private key to manage. It also conflicts with the SPIFFE-SVID trust model the platform is committed to.

Proposal

Add a third path: language-runtime hooks that intercept outbound HTTPS at the application layer, before TLS encryption, and route it as plaintext to a new AuthBridge listener for full pipeline processing. AuthBridge then re-originates a real TLS connection to the upstream.

This avoids TLS-bumping entirely. The upstream sees a normal TLS handshake with valid certs (originated by AuthBridge, validated against system roots). The agent sees a normal HTTPS API. AuthBridge sees plaintext.

Hook mechanism per runtime

Runtime Injection vector Coverage
Node.js NODE_OPTIONS=--require=/opt/kagenti/intercept.js Patches https.request, undici global dispatcher (catches fetch, @anthropic-ai/sdk, openai SDK)
Python PYTHONPATH=/opt/kagenti + sitecustomize.py Patches httpx, requests, aiohttp

For v1, Node + Python covers the bulk of the agent ecosystem (Claude Code, Cursor, LangGraph, CrewAI, AG2, openai-python, anthropic-python). Java (-javaagent:) and others can follow.

Hook behavior

The hook does the minimum: rewrite the HTTPS request to a plaintext HTTP request aimed at the local AuthBridge hook listener, preserving the original target via headers. The hook does not implement policy, token exchange, or any pipeline logic — that all stays in AuthBridge.

agent code: openai.chat.completions.create(...)
    ↓
undici / httpx
    ↓ (intercepted by hook)
http://127.0.0.1:8081/v1/chat/completions
  + Host: api.openai.com
  + X-Kagenti-Target-Scheme: https
  + X-Kagenti-Target-Port: 443
    ↓
AuthBridge hook listener
  → pipeline (ibac, mcp-parser, inference-parser, token-exchange)
  → upstream TLS dial to api.openai.com:443

AuthBridge changes (scoped)

  • New plaintext listener (hookproxy/server.go), loopback-bound, separate from the existing forward-proxy listener.
  • Header parser for X-Kagenti-Target-{Scheme,Port} to construct pipeline.Context with the original destination.
  • Upstream TLS dialer for HTTPS re-origination. Uses system trust roots (same set the agent would have used). HTTP/2 negotiation, streaming bodies (SSE for LLM streaming).
  • Existing pipeline, plugins, finisher, session machinery all unchanged.

Operator changes (kagenti-operator)

Inject on agent containers:

  • KAGENTI_AUTHBRIDGE_URL=http://127.0.0.1:8081
  • KAGENTI_AUTHBRIDGE_BYPASS=<comma-separated hostnames> (cert-pinned destinations)
  • NODE_OPTIONS=--require=/opt/kagenti/intercept.js
  • PYTHONPATH=/opt/kagenti:${PYTHONPATH}
  • Volume mount for /opt/kagenti (ConfigMap-backed, hooks shipped from AuthBridge release)

Layered with #430

Three modes selected per-request:

  1. Hook + plaintext-to-AuthBridge — for HTTPS to non-bypassed destinations on supported runtimes. Full pipeline, modify, re-originate.
  2. Hook bypass → straight HTTPS — for cert-pinned destinations the operator allowlists. No inspection.
  3. HTTPS_PROXY → CONNECT tunnel (✨ feat(forwardproxy): support HTTPS CONNECT as raw TCP passthrough #430) — for unsupported runtimes (Go binaries) or agents that don't honor NODE_OPTIONS. Destination policy only.

The bypass list shrinks over time as language hooks get added and pinning issues are characterized.

Capabilities unlocked

For Node + Python agents (the common case):

  • Token exchange on HTTPS — placeholder Authorization replaced with real provider keys at the AuthBridge layer. The "fundamentally not possible" caveat in ✨ feat(forwardproxy): support HTTPS CONNECT as raw TCP passthrough #430 goes away for these runtimes.
  • Inference-parser on HTTPS — token counting, model auditing, prompt logging on api.openai.com / api.anthropic.com traffic.
  • MCP-parser on HTTPS — MCP-over-HTTPS to remote MCP servers.
  • Content-aware ibac policy — body inspection beyond destination host.
  • Session events for HTTPS in /v1/sessions — parity with HTTP.

Costs

  • Per-runtime hook implementation; v1 = Node + Python.
  • Hook is environment-level cooperation (env var + mounted file). Not a security boundary against adversarial agents — they can delete process.env.NODE_OPTIONS. Pair with eBPF audit (separate issue) for independent verification.
  • Localhost loopback hop adds a small per-request overhead. SSE streaming validated end-to-end before merge.
  • AuthBridge needs trust-store parity with the agent for upstream TLS validation (NODE_EXTRA_CA_CERTS-equivalent in OpenShift environments).

Open questions

  • Hook listener port: dedicated :8081 or sub-path on existing :8080?
  • Header naming: X-Kagenti-Target-* or align with an existing convention?
  • Bypass detection — config-driven only (operator allowlist) or also runtime-detected (parse cert errors back from agent)?
  • How to handle adversarial-runtime case (agent strips NODE_OPTIONS)? Audit-only via eBPF, or hard-fail-closed via network policy?
  • Hook distribution: ConfigMap from AuthBridge release vs. baked into agent images vs. init-container copy.
  • Streaming response handling — verify SSE round-trip with Anthropic streaming endpoint before merge.

Scope for v1

  • New hookproxy listener in AuthBridge (Go).
  • Node hook (intercept.js) covering https.request + undici dispatcher.
  • Python hook (sitecustomize.py) covering httpx.
  • ConfigMap distribution wired through kagenti-operator.
  • Tests: hook redirects HTTPS to AuthBridge; pipeline runs on rewritten request; upstream TLS dial succeeds; SSE streaming works; bypass list honored.

Out of scope for v1: Java/Ruby/.NET hooks; full Python coverage of requests and aiohttp (add as follow-ups); adversarial-runtime hardening; eBPF audit integration.

References

Assisted-By: Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions