Skip to content

security: close telemetry leak in preconnectAnthropicApi startup path#1253

Merged
claude-code-best merged 1 commit into
claude-code-best:mainfrom
GhostDragon124:fix/preconnect-privacy-gate
Jun 2, 2026
Merged

security: close telemetry leak in preconnectAnthropicApi startup path#1253
claude-code-best merged 1 commit into
claude-code-best:mainfrom
GhostDragon124:fix/preconnect-privacy-gate

Conversation

@GhostDragon124
Copy link
Copy Markdown
Contributor

@GhostDragon124 GhostDragon124 commented Jun 1, 2026

🔒 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)

Summary by CodeRabbit

  • Bug Fixes
    • App now respects the "essential traffic only" configuration by skipping unnecessary API preconnections when this mode is enabled.

🔒 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)
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a privacy-aware guard to the Anthropic API preconnection function. When the application is configured to allow only essential traffic, preconnectAnthropicApi() now returns early and skips the fire-and-forget TCP+TLS preconnect attempt.

Changes

Essential Traffic Configuration

Layer / File(s) Summary
Essential traffic check in preconnect
src/utils/apiPreconnect.ts
Imports isEssentialTrafficOnly() and adds an early return guard to skip Anthropic API preconnection when non-essential traffic is disabled via privacy or essential-traffic configuration.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A preconnect skips when traffic flows sparse,
When isEssentialTrafficOnly() guards the sparse,
Privacy-first, the rabbit does declare—
No wasteful DNS when essentials are rare! 🌕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main security fix: closing a telemetry leak in the preconnectAnthropicApi startup path by adding privacy-gated behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/apiPreconnect.ts`:
- Line 28: The import in src/utils/apiPreconnect.ts currently uses a relative
path for isEssentialTrafficOnly; replace the relative import
("./privacyLevel.js") with the project alias form (e.g., import from
'src/utils/privacyLevel' or 'src/utils/privacyLevel.js' depending on codebase
conventions) so it uses the configured src/* mapping; update the import
statement that references isEssentialTrafficOnly accordingly and run a quick
typecheck to ensure the alias resolves.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c9cda14-c135-491d-b228-88b80eba349c

📥 Commits

Reviewing files that changed from the base of the PR and between b2b1981 and 015901d.

📒 Files selected for processing (1)
  • src/utils/apiPreconnect.ts


import { getOauthConfig } from '../constants/oauth.js'
import { isEnvTruthy } from './envUtils.js'
import { isEssentialTrafficOnly } from './privacyLevel.js'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use src/* alias for this new import.

Please switch this new relative import to the configured alias form to match repo rules.

Suggested diff
-import { isEssentialTrafficOnly } from './privacyLevel.js'
+import { isEssentialTrafficOnly } from 'src/utils/privacyLevel.js'

As per coding guidelines, "Import paths must use the src/* alias (e.g., import { ... } from 'src/utils/...'); tsconfig maps src/* to ./src/*."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { isEssentialTrafficOnly } from './privacyLevel.js'
import { isEssentialTrafficOnly } from 'src/utils/privacyLevel.js'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/apiPreconnect.ts` at line 28, The import in
src/utils/apiPreconnect.ts currently uses a relative path for
isEssentialTrafficOnly; replace the relative import ("./privacyLevel.js") with
the project alias form (e.g., import from 'src/utils/privacyLevel' or
'src/utils/privacyLevel.js' depending on codebase conventions) so it uses the
configured src/* mapping; update the import statement that references
isEssentialTrafficOnly accordingly and run a quick typecheck to ensure the alias
resolves.

Copy link
Copy Markdown
Owner

@claude-code-best claude-code-best left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Simple, consistent, and verifiable.

What this does: Adds isEssentialTrafficOnly() gate at preconnectAnthropicApi() entry — the same pattern already used by bootstrap.ts, grove.ts, releaseNotes.ts, and 9 other modules in the codebase.

Why it's correct:

  • The preconnect sends a TCP+TLS handshake to api.anthropic.com on startup. It's a performance optimization (warm the connection pool), not a functional requirement.
  • When CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1, users intend zero non-user-requested outbound connections. This was the last un-gated one.
  • The check is a pure env-var read with no I/O — zero perf impact on the gate itself.
  • Placement after the fired guard is correct: it avoids any module-level side effects if the function is never called.

Verification: Existing tests pass (bun test src/utils/__tests__/privacyLevel.test.ts → 12/12). The typecheck has only the pre-existing bun type-def issue, zero new errors.

@claude-code-best claude-code-best merged commit 02298cb into claude-code-best:main Jun 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants