[BUG] Remote Control bridge registration sent as plaintext HTTP through proxy instead of CONNECT-tunneling

Status Open
Reported on v2.1.193
Maintainer reply None cached
Activity 3 comments · opened Jun 27, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

Remote Control fails to register whenever an HTTP proxy is configured via HTTPS_PROXY / HTTP_PROXY. claude remote-control (and --remote-control, and remoteControlAtStartup: true) aborts at registration with an HTTP 400.

The Remote Control bridge client does not CONNECT-tunnel HTTPS through the proxy. It sends the registration request to the proxy in forward-proxy absolute-form over a cleartext connection, so the upstream receives plaintext and rejects it. The normal Anthropic API client works fine over the same proxy (it CONNECT-tunnels correctly), so only the Remote Control bridge path is broken.

Side effect: the Authorization: Bearer token is transmitted in cleartext to the proxy and onward (the error message itself warns about this). With remoteControlAtStartup: true, this fires on every session start.

What Should Happen?

The bridge client should honor HTTPS_PROXY by issuing CONNECT api.anthropic.com:443 and then performing TLS to the origin, exactly as the main Anthropic API client already does. Registration should succeed through an HTTP proxy, and the bearer token should never be sent in cleartext.

Error Messages/Logs

Error: Registration: Failed with status 400: This request was sent over HTTP. Only HTTPS is supported for API use. Consider revoking your API key, as it was sent in plaintext over the internet with this request.

# What the bridge client actually sends to the proxy, captured by pointing
# HTTPS_PROXY at a local logging listener:
POST https://api.anthropic.com/v1/environments/bridge HTTP/1.1
Authorization: Bearer sk-ant-oat01-<REDACTED>
anthropic-version: 2023-06-01
anthropic-beta: environments-2025-11-01
x-environment-runner-version: 2.1.193
User-Agent: claude

# Expected instead: a CONNECT tunnel ->  CONNECT api.anthropic.com:443  (then TLS to origin)

Steps to Reproduce

  1. Start any HTTP forward proxy locally, e.g. tinyproxy / squid / mitmproxy on 127.0.0.1:8888 (or a tiny TCP listener that logs the first bytes, to inspect what the client emits).
  2. Launch Remote Control through it:

``
HTTPS_PROXY=http://127.0.0.1:8888 HTTP_PROXY=http://127.0.0.1:8888 \
claude remote-control --spawn=same-dir
``

  1. Registration fails immediately with the HTTP 400 shown above.
  2. To confirm the cause: point HTTPS_PROXY at a listener that logs the first request bytes. The client sends POST https://api.anthropic.com/v1/environments/bridge HTTP/1.1 (absolute-form, cleartext) instead of CONNECT api.anthropic.com:443.

Notes:

  • The normal API path over the same proxy works (it CONNECT-tunnels), so this is specific to the bridge client.
  • Tried and did not help: NODE_USE_ENV_PROXY=1; HTTPS_PROXY only (with HTTP_PROXY unset); ALL_PROXY. All reproduce the identical error.

Claude Model

Not sure / Multiple models (not model-related; this is a networking/registration bug).

Is this a regression?

No, this never worked.

Claude Code Version

2.1.193 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other (terminal-independent; reproduces in a non-interactive invocation too).

Additional Information

  • Root cause is in the bridge client's proxy handling, not the proxy itself: a forward HTTP proxy correctly CONNECT-tunnels the main client's HTTPS to api.anthropic.com; only the /v1/environments/bridge registration is emitted in absolute-form cleartext.
  • Security impact worth prioritizing: the OAuth bearer token (sk-ant-oat01-...) is sent in cleartext, and remoteControlAtStartup: true triggers this on every session start.
  • Searched existing issues before filing. Closest are #65801 (distinct: bridge is reachable, token rejected upstream) and #1382 (old main-client corporate-proxy 400, since fixed). This report is specifically the Remote Control bridge client not CONNECT-tunneling through an HTTP proxy.

View original on GitHub ↗

3 Comments

yurukusa · 2 months ago

Not a maintainer — flagging the containment step, because the diagnosis here is solid and the security impact is bigger than a failed registration.
The token is already compromised — treat it as exposed and rotate it now. Your capture shows the full Authorization: Bearer sk-ant-oat01-… going out in cleartext to the proxy (and the 400 from the origin literally tells you to revoke it). That OAuth access token has now traversed at least the proxy hop in the clear; with remoteControlAtStartup: true it has done so on every session start since you configured the proxy. The failed registration is the visible symptom; the leaked bearer is the actual incident. Containment, in order:

  1. Rotate first. Re-authenticate so a fresh token is issued and the leaked one stops being the active credential: claude/login (or log out and back in). If your account settings expose active sessions / API credentials, revoke the old one there; if not, treat the exposed token as live until it expires and consider contacting support to invalidate it.
  2. Stop re-triggering the leak until the bridge path is fixed: set remoteControlAtStartup: false (or unset it) and don't run claude remote-control / --remote-control while an HTTP_PROXY / HTTPS_PROXY is active. Every invocation behind the forward proxy re-sends the bearer in cleartext.
  3. Confirm the boundary. Your own contrast is the key evidence and worth keeping in the report: the normal Anthropic API client CONNECT-tunnels correctly through the same proxy, so this is isolated to the Remote Control bridge client's proxy handling — not your proxy, not your env. That's exactly the right scoping for the maintainers.

Why the operator can't fully fix it: the correct behavior (issue CONNECT api.anthropic.com:443, then TLS to origin, so the bearer is never in cleartext) is in the bridge client and has to be fixed there — same as the related HTTPS_PROXY https://-scheme gap. Nothing on the operator side makes a forward-proxy + Remote Control combination safe today; the only safe operator posture is to keep Remote Control off the proxied path until the client honors the tunnel.
One question that helps the maintainers triage severity: was the proxy on a trusted local host (e.g. 127.0.0.1 mitmproxy for your own capture), or a real network/corporate egress proxy? The blast radius of the cleartext bearer is very different between the two, and stating it sets the right priority.

NiraNora · 1 month ago

I'm running into a similar problem with claude remote-control behind a forward proxy (Squid).

Environment:

  • Docker container with HTTPS_PROXY=http://proxy:3128 / HTTP_PROXY=http://proxy:3128
  • Squid proxy configured to allow CONNECT to api.anthropic.com:443

Observed behavior:

The bridge client sends requests with the proxy's own port appended to the target host, instead of issuing a proper CONNECT api.anthropic.com:443 first:

POST https://api.anthropic.com:3128/v1/environments/bridge 
POST https://api.anthropic.com:3128/api/event_logging/v2/batch

Squid logs confirm the tunnel is accepted but the upstream connection never completes (since api.anthropic.com obviously isn't listening on port 3128):

1783285585.066 15005 10.10.1.4 TCP_MISS_ABORTED/000 0 POST https://api.anthropic.com:3128/v1/environments/bridge - HIER_NONE/- - 1783285585.133 5112 10.10.1.4 TCP_MISS_ABORTED/000 0 POST https://api.anthropic.com:3128/api/event_logging/v2/batch - HIER_NONE/- -

Would be great to see this fixed — happy to provide more logs/config if useful.

y-cruce · 3 days ago

Still reproducible on 2.1.246 and 2.1.247 (macOS, official build), and I can add the root cause plus a verified fix.

Root cause: the bridge client performs /v1/environments/bridge (and the rest of the bridge API) through the bundled axios instance, and axios's built-in env-proxy support never CONNECT-tunnels. When HTTPS_PROXY is set, axios rewrites the request to {host: <proxy>, path: "https://api.anthropic.com/…"} and picks the transport from the proxy's protocol (http:), so the request leaves as absolute-form cleartext HTTP — a long-standing axios adapter limitation. The main API client uses a different HTTP stack that tunnels correctly, which is why everything else works over the same proxy and only the bridge path breaks.

Captured from inside the process on 2.1.247 (hooking http.request):

POST via http:// to 127.0.0.1:20813 (local proxy), path = "https://api.anthropic.com/v1/environments/bridge"
→ 400, content-type: text/html (Cloudflare): "The plain HTTP request was sent to HTTPS port"

Depending on which edge answers, the 400 body is either the plaintext-HTTP API error the OP quoted or this Cloudflare HTML page; in the HTML case the CLI shows only the bare Registration: Failed with status 400 with no detail, which makes it look like an account/permissions problem.

Verified fix: I patched http.request so that calls whose path is an absolute https:// URL (only axios's proxy mode produces those) are reissued as real HTTPS requests through a CONNECT tunnel to the proxy. With that in place, claude remote-control works fully behind HTTPS_PROXY=http://127.0.0.1:20813 on 2.1.247 — registration returns 200, polling, session spawn and heartbeats all function. So fixing the bridge client's axios config (proxy: false plus a CONNECT-capable agent — an HttpsProxyAgent is already bundled for other subsystems) or routing these calls through the same stack as the main API client would resolve this.

Worth repeating the OP's security point: until this is fixed, every registration attempt sends the OAuth bearer token as cleartext beyond the proxy, so affected users should rotate credentials after testing.