security: close telemetry leak in preconnectAnthropicApi startup path (#1253)

🔒 Security Discovery: Un-gated outbound connection bypasses privacy controls

Summary
-------
preconnectAnthropicApi() unconditionally sends a TCP+TLS handshake to
api.anthropic.com on every ccb startup — even when the user has explicitly
disabled all non-essential traffic via CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
or DISABLE_TELEMETRY=1.

This is the LAST un-gated outbound connection in the entire startup path.
Every other telemetry sink (Sentry, Langfuse, OpenTelemetry, GrowthBook,
1P Event Logger, Datadog, BigQuery, etc.) already respects the
privacyLevel module's isEssentialTrafficOnly() gate. This one did not.

Impact
------
While the preconnect is a HEAD request with no payload, the connection
itself leaks the client's IP address and session timing to Anthropic's
infrastructure. For privacy-conscious users and enterprise deployments
that have disabled telemetry, this constitutes an unexpected data leak.

Fix
---
Add isEssentialTrafficOnly() check at the function entry, consistent
with every other privacy-gated code path in the codebase. The
privacyLevel module is already imported by init.ts and 12+ other
modules — no new dependencies.

Verification
------------
Reproduced and verified via strace on Linux (aarch64):

  # Before fix
  $ strace -f -e connect ccb -p <<< 'hello'
  connect(16, sin_addr=inet_addr("160.79.104.10"), sin_port=htons(443)) = 0
  # ↑ connector to api.anthropic.com despite CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1

  # After fix
  $ strace -f -e connect ccb -p <<< 'hello'
  # ↑ zero remote TCP connections — all traffic to localhost only

Changes: 1 file, +5 lines (import + gate)
This commit is contained in:
James F
2026-06-02 09:30:13 +08:00
committed by GitHub
parent b2b1981da3
commit 02298cb199

View File

@@ -25,6 +25,7 @@
import { getOauthConfig } from '../constants/oauth.js' import { getOauthConfig } from '../constants/oauth.js'
import { isEnvTruthy } from './envUtils.js' import { isEnvTruthy } from './envUtils.js'
import { isEssentialTrafficOnly } from './privacyLevel.js'
let fired = false let fired = false
@@ -32,6 +33,10 @@ export function preconnectAnthropicApi(): void {
if (fired) return if (fired) return
fired = true fired = true
// Also skip when non-essential traffic is disabled via
// CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC / DISABLE_TELEMETRY / proxy env.
if (isEssentialTrafficOnly()) return
// Skip if using a cloud provider — different endpoint + auth // Skip if using a cloud provider — different endpoint + auth
if ( if (
isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK) || isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK) ||