Skip to content

feat(cli): anonymous opt-out usage analytics + stash telemetry#644

Open
coderdan wants to merge 3 commits into
mainfrom
feat/cli-anonymous-telemetry
Open

feat(cli): anonymous opt-out usage analytics + stash telemetry#644
coderdan wants to merge 3 commits into
mainfrom
feat/cli-anonymous-telemetry

Conversation

@coderdan

@coderdan coderdan commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Adds anonymous, opt-out usage analytics to the stash CLI, a stash telemetry [status|enable|disable] command to manage it, and the Cloudflare reverse proxy the CLI reports through. Stacked on the EQL v3 RC (feat/eql-v3-text-search-schema, #535).

What it collects

Coarse events only: command name, CLI version, OS/arch, success/failure, duration, and the error class on failure. A property allowlist enforced at the emitter boundary (sanitize in telemetry/index.ts) makes it structurally impossible for plaintext, schema, table/column names, connection strings, or argument values to leave the machine — this is the load-bearing guarantee for a zero-knowledge product, and it has direct tests.

Behaviour

  • Opt-out by default, Homebrew-style: a one-time notice prints to stderr on first run, and nothing is sent on the run that shows it.
  • Four opt-out gates (any one wins; env overrides beat the saved preference): DO_NOT_TRACK=1 (cross-tool standard), STASH_TELEMETRY_DISABLED=1, CI auto-detect, and persisted stash telemetry disable.
  • Anonymous: a random salted machine ID; PostHog person profiles disabled.
  • Never blocks the CLI: lazy client, posthog-node events-only, flush bounded by a 1.5s timeout, all failures swallowed.
  • State lives in ~/.cipherstash/telemetry.json — a non-secret file distinct from the auth credentials.

Proxy (infra/telemetry-proxy/)

A Cloudflare Worker forwards telemetry.cipherstash.com → PostHog, with the target host in a POSTHOG_HOST variable. This makes the deferred US→EU PostHog migration a var-change + redeploy with no CLI re-release — every installed stash follows the proxy. It's an allowlisted forwarder, not an open proxy.

Ships dormant

The embedded PostHog key is a placeholder, so telemetry is fully inert (resolveStatusunconfigured, no banner, no sends) until the real public write-only key is embedded at release. Safe to merge before the infra is live.

Tests

423 CLI tests pass, including 16 new ones covering gate precedence, CI detection, the allowlist (asserts table/databaseUrl/plaintext etc. are dropped), and state roundtrip/corruption recovery.

Follow-ups (outside this PR)

  • Deploy the Worker (infra/telemetry-proxy/README.md) and embed the real PostHog key at release.
  • Publish the cipherstash.com/docs/reference/cli page the first-run notice links to.

Notes

  • posthog-node was already a vetted dependency; it's newly used here.
  • Updates skills/stash-cli/SKILL.md (new command + Telemetry section) — hence the stash changeset.

https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w

Summary by CodeRabbit

  • New Features

    • Added anonymous, opt-out usage analytics for the stash CLI.
    • Added stash telemetry status|enable|disable for managing analytics preferences.
    • Telemetry remains disabled in CI and supports environment-based opt-out controls.
    • Added safeguards to collect only coarse usage data without sensitive command details.
    • Improved detection of common CI environments.
  • Documentation

    • Added telemetry guidance to the CLI skill documentation and release notes.
    • Documented the telemetry proxy and deployment configuration.

Add anonymous, opt-out usage analytics to the stash CLI, plus a
`stash telemetry [status|enable|disable]` command to manage it.

- Coarse events only (command, version, OS/arch, success, duration);
  a property allowlist at the emitter boundary makes it impossible for
  plaintext, schema, table/column names, connection strings, or argument
  values to leave the machine.
- Opt-out by default, Homebrew-style: nothing is sent until the one-time
  first-run notice has been shown once. Four opt-out gates in precedence
  order: DO_NOT_TRACK, STASH_TELEMETRY_DISABLED, CI auto-detect, and the
  persisted `stash telemetry disable` flag in ~/.cipherstash/telemetry.json.
- Events go through a first-party Cloudflare proxy (infra/telemetry-proxy),
  so a future US->EU PostHog move is a proxy-target change with no CLI
  re-release. posthog-node, events-only (no person profiles), lazy client,
  flush bounded by a timeout so it never blocks or slows the CLI.
- Ships dormant: no events are sent until a real PostHog key is embedded
  at release (STASH_POSTHOG_KEY overrides for testing).

Updates the stash-cli skill and adds a changeset.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
@coderdan coderdan requested a review from a team as a code owner July 14, 2026 03:50
@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9048fc6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
stash Minor
@cipherstash/e2e Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds anonymous, opt-out CLI telemetry with persisted settings, CI-aware gating, allowlisted event fields, stash telemetry controls, lifecycle integration, and a Cloudflare Worker proxy forwarding permitted requests to PostHog.

Changes

CLI telemetry

Layer / File(s) Summary
CI detection and test isolation
packages/cli/src/config/tty.ts, packages/cli/src/__tests__/database-url.test.ts, packages/cli/src/commands/auth/__tests__/region.test.ts, packages/cli/tests/helpers/pty.ts
CI detection now includes standard and provider-specific markers, while affected tests sanitize and restore those variables.
Persisted telemetry state
packages/cli/src/telemetry/state.ts, packages/cli/src/telemetry/__tests__/state.test.ts
Telemetry state is normalized and stored in a private JSON file, with defaults and recovery for invalid data.
Telemetry gating and event lifecycle
packages/cli/src/telemetry/index.ts, packages/cli/src/telemetry/__tests__/telemetry.test.ts
Telemetry enablement, opt-out precedence, property allowlisting, first-run disclosure, command tracking, and bounded shutdown flushing are implemented and tested.
CLI command and user-facing integration
packages/cli/src/bin/main.ts, packages/cli/src/commands/telemetry/index.ts, packages/cli/src/cli/registry.ts, packages/cli/src/messages.ts, packages/cli/src/commands/index.ts, .changeset/cli-anonymous-telemetry.md, skills/stash-cli/SKILL.md
The telemetry command is registered and routed, command execution emits lifecycle events, and documentation describes controls and collected fields.
Telemetry proxy infrastructure
infra/telemetry-proxy/worker.js, infra/telemetry-proxy/wrangler.toml, infra/telemetry-proxy/README.md
A Cloudflare Worker validates allowed methods and paths before forwarding requests to the configured PostHog host.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: auxesis, calvinbrewer

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.06% 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 clearly summarizes the main change: anonymous opt-out telemetry and the new stash telemetry command.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cli-anonymous-telemetry

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.

Copilot AI left a comment

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.

Pull request overview

Adds an anonymous, opt-out telemetry system to the stash CLI (with a persisted machine-level state file), introduces a stash telemetry [status|enable|disable] command to manage the saved preference, and includes a Cloudflare Worker reverse-proxy so the CLI reports to a first-party endpoint that can be retargeted without re-releasing the CLI.

Changes:

  • Implement CLI telemetry capture with opt-out gating, a one-time first-run notice, property allowlisting, and bounded shutdown flushing.
  • Add stash telemetry subcommand + registry/docs wiring.
  • Add infra/telemetry-proxy/ Cloudflare Worker + deploy docs, plus a changeset for the CLI change.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
skills/stash-cli/SKILL.md Documents the new telemetry command and opt-out mechanisms in the published CLI skill.
packages/cli/src/telemetry/state.ts Implements persisted telemetry state (~/.cipherstash/telemetry.json) with corruption tolerance and 0600 permissions.
packages/cli/src/telemetry/index.ts Telemetry core: gating, allowlist sanitization, PostHog client creation, first-run notice, capture + shutdown flush.
packages/cli/src/telemetry/tests/telemetry.test.ts Adds tests for gate precedence and property allowlist behavior.
packages/cli/src/telemetry/tests/state.test.ts Adds tests for telemetry state persistence and corruption recovery.
packages/cli/src/messages.ts Adds the first-run telemetry notice and stash telemetry UX strings.
packages/cli/src/commands/telemetry/index.ts Implements `stash telemetry [status
packages/cli/src/commands/index.ts Exports the new telemetry command.
packages/cli/src/cli/registry.ts Registers telemetry in the CLI command registry/help surface.
packages/cli/src/bin/main.ts Wires telemetry init/notice/tracking/shutdown into the main CLI dispatch path.
infra/telemetry-proxy/wrangler.toml Adds Worker config for telemetry.cipherstash.com and POSTHOG_HOST target var.
infra/telemetry-proxy/worker.js Implements allowlisted-path reverse proxy to PostHog ingestion endpoints.
infra/telemetry-proxy/README.md Adds deploy + verification instructions for the proxy Worker.
.changeset/cli-anonymous-telemetry.md Records the CLI user-facing feature addition for release notes/versioning.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/cli/src/telemetry/index.ts
Comment thread packages/cli/src/telemetry/index.ts
Comment thread packages/cli/src/messages.ts Outdated
Comment thread packages/cli/src/telemetry/__tests__/state.test.ts
Comment thread infra/telemetry-proxy/worker.js Outdated
Review findings:
- shutdownTelemetry: clear the flush-timeout timer so a fast flush no longer
  leaves a dangling setTimeout that hangs the process for the full timeout; also
  set fetchRetryCount:0 so an unreachable endpoint fails fast instead of
  retrying with backoff (which kept internal timers alive and hung the CLI for
  seconds). Enabled commands now exit in ~140ms even when the endpoint is down.
- First-run notice: persist noticeShownAt ONLY when the notice was actually
  displayed (stderr is a TTY), so a non-interactive first run no longer consumes
  the freebie and starts sending without the user ever seeing the disclosure.
- Broaden DO_NOT_TRACK / STASH_TELEMETRY_DISABLED to opt out on any non-empty
  value except 0/false (matches the DO_NOT_TRACK convention).
- Reuse the shared isCiEnv() from config/tty.ts instead of a second, divergent
  CI detector; widen isCiEnv() with provider markers (GITHUB_ACTIONS, GITLAB_CI,
  Azure TF_BUILD, Jenkins, TeamCity, …) so telemetry never fires in CI even when
  a provider doesn't set CI=true. Export CI_ENV_VARS and make the region /
  database-url tests hermetic against those ambient vars.
- Drop the dead resolveStatus() re-resolve after writing the notice.

Copilot:
- Sanitize the combined event+base props so the allowlist is the single enforced
  boundary (a future baseProps field can't bypass it).
- Make the first-run opt-out hint runner-aware (npx stash …) so it's actionable
  before stash is on PATH.
- Restore process.env.HOME in the state test so it can't leak across test files.
- Worker returns 500 when POSTHOG_HOST is unset instead of forwarding to an
  invalid host.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
@coderdan

Copy link
Copy Markdown
Contributor Author

Addressed the review + Copilot feedback in ad77675.

Copilot comments

  • Notice persisted without display (index.ts:212): noticeShownAt is now written only when the notice is actually shown (stderr is a TTY), so a non-interactive first run no longer consumes the freebie and starts sending without disclosure.
  • Allowlist boundary (index.ts:190): now sanitize the combined event + base props, so the allowlist is the single enforced boundary and a future baseProps() field can't bypass it.
  • npx vs stash on PATH (messages.ts): the opt-out hint is now runner-aware (npx stash telemetry disable) and also names DO_NOT_TRACK=1, so it's actionable before stash is on PATH.
  • HOME not restored (state.test.ts): the test now snapshots and restores process.env.HOME in afterEach.
  • Worker POSTHOG_HOST unset (worker.js): returns a 500 instead of forwarding to an invalid host.

Review findings also fixed

  • The flush timer is now cleared (and fetchRetryCount: 0 set) so an enabled command exits in ~140ms even against an unreachable endpoint, instead of hanging.
  • DO_NOT_TRACK / STASH_TELEMETRY_DISABLED now opt out on any non-empty value except 0/false.
  • CI detection is unified on the shared isCiEnv() (config/tty.ts), widened with provider markers (GitHub, GitLab, Azure TF_BUILD, Jenkins, TeamCity, …) so telemetry never fires in CI even when a provider doesn't set CI=true.

425 tests pass; Biome clean.

Base automatically changed from feat/eql-v3-text-search-schema to main July 14, 2026 04:31
Widening isCiEnv() with provider markers (GITHUB_ACTIONS, GITLAB_CI, …) made the
pty e2e harness leak this repo's own CI env into the spawned CLI: the harness
defaults CI=true and interactive tests override with `CI: ''`, but that no longer
fully de-CIs the environment once GITHUB_ACTIONS=true is also present, so
`auth login` skipped the region prompt and the test timed out.

Strip every CI signal (CI_ENV_VARS) from the child env before applying the
harness's CI default and per-test overrides, so CI detection is fully controlled
by the harness — matching how the unit tests were made hermetic. Verified the
full e2e suite passes with GITHUB_ACTIONS=true CI=true exported.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli/src/bin/main.ts (1)

537-540: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid process.exit() in these unknown-command branches — it short-circuits run()’s finally, so the telemetry event/flush never runs on typo/error exits. Throw instead, or flush before exiting, in packages/cli/src/bin/main.ts#L537-L540 and packages/cli/src/commands/telemetry/index.ts#L60-L63.

🤖 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 `@packages/cli/src/bin/main.ts` around lines 537 - 540, Replace the direct
process.exit() calls in the unknown-command branches of
packages/cli/src/bin/main.ts lines 537-540 and
packages/cli/src/commands/telemetry/index.ts lines 60-63 with thrown errors so
run() reaches its finally block and telemetry flushes; preserve the existing
error message and help output.
🧹 Nitpick comments (3)
packages/cli/src/__tests__/database-url.test.ts (1)

43-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract duplicate test helpers to a shared module.

These test files contain identical logic for managing provider CI environment variables. Extracting this setup into a shared helper (e.g., in packages/cli/tests/helpers/) will keep the test suite DRY and easier to maintain.

  • packages/cli/src/__tests__/database-url.test.ts#L43-L66: extract the duplicated savedProviderCi, neutralizeProviderCi, and restoreProviderCi logic into a shared test helper.
  • packages/cli/src/commands/auth/__tests__/region.test.ts#L33-L56: replace this duplicated logic with an import from the new shared test helper.
🤖 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 `@packages/cli/src/__tests__/database-url.test.ts` around lines 43 - 66,
Extract the duplicated savedProviderCi, neutralizeProviderCi, and
restoreProviderCi logic into a shared test helper under
packages/cli/tests/helpers/, preserving exact environment restoration and CI
handling. In packages/cli/src/__tests__/database-url.test.ts:43-66, replace the
local state and functions with imports from the helper; apply the same
replacement in packages/cli/src/commands/auth/__tests__/region.test.ts:33-56.
packages/cli/src/telemetry/__tests__/telemetry.test.ts (1)

1-169: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding lifecycle coverage for trackCommand/maybeShowFirstRunNotice/shutdownTelemetry.

This suite thoroughly covers resolveStatus/sanitize (both pure), but the side-effecting lifecycle functions that depend on module-level state/status/firstRun are untested here. Since those variables are captured once at import time, exercising them would need vi.resetModules() + dynamic re-import per test — worth doing given they encode the "freebie first run" and "no-op when disabled" guarantees the PR relies on.

🤖 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 `@packages/cli/src/telemetry/__tests__/telemetry.test.ts` around lines 1 - 169,
Extend the telemetry test suite with lifecycle coverage for trackCommand,
maybeShowFirstRunNotice, and shutdownTelemetry using vi.resetModules() and
dynamic imports per test so module-level state, status, and firstRun are
reinitialized. Verify the enabled first-run/freebie behavior and that disabled
telemetry paths are no-ops, reusing the existing environment setup and mocks
where needed.
packages/cli/src/commands/telemetry/index.ts (1)

10-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Centralize these status strings in messages.ts for consistency.

enabled/disabled/unknownSubcommand already pull from messages.telemetry, but reasonText's per-reason strings and printStatus's info lines are inlined here instead. If any E2E test ever asserts on this copy, it'll need to track two places instead of one.

As per path instructions: "Keep assertion-stable user-facing strings in src/messages.ts and update the constants there when E2E tests assert on copy such as cancellation text, 'Unknown auth command', or the db migrate stub warning."

🤖 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 `@packages/cli/src/commands/telemetry/index.ts` around lines 10 - 38, Move the
user-facing telemetry status and reason strings used by reasonText and
printStatus into the existing telemetry section of messages.ts, alongside
enabled, disabled, and unknownSubcommand. Update these functions to reference
the centralized message constants while preserving the current wording and
status-specific behavior.

Source: Path instructions

🤖 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 `@infra/telemetry-proxy/worker.js`:
- Around line 48-49: Update the forwarded request construction in the proxy
handler to remove IP-revealing headers, including CF-Connecting-IP and
X-Forwarded-For, after copying the incoming request headers and before
forwarding to PostHog. Preserve the existing Host header assignment while
ensuring these anonymity-sensitive headers cannot reach the target.

---

Outside diff comments:
In `@packages/cli/src/bin/main.ts`:
- Around line 537-540: Replace the direct process.exit() calls in the
unknown-command branches of packages/cli/src/bin/main.ts lines 537-540 and
packages/cli/src/commands/telemetry/index.ts lines 60-63 with thrown errors so
run() reaches its finally block and telemetry flushes; preserve the existing
error message and help output.

---

Nitpick comments:
In `@packages/cli/src/__tests__/database-url.test.ts`:
- Around line 43-66: Extract the duplicated savedProviderCi,
neutralizeProviderCi, and restoreProviderCi logic into a shared test helper
under packages/cli/tests/helpers/, preserving exact environment restoration and
CI handling. In packages/cli/src/__tests__/database-url.test.ts:43-66, replace
the local state and functions with imports from the helper; apply the same
replacement in packages/cli/src/commands/auth/__tests__/region.test.ts:33-56.

In `@packages/cli/src/commands/telemetry/index.ts`:
- Around line 10-38: Move the user-facing telemetry status and reason strings
used by reasonText and printStatus into the existing telemetry section of
messages.ts, alongside enabled, disabled, and unknownSubcommand. Update these
functions to reference the centralized message constants while preserving the
current wording and status-specific behavior.

In `@packages/cli/src/telemetry/__tests__/telemetry.test.ts`:
- Around line 1-169: Extend the telemetry test suite with lifecycle coverage for
trackCommand, maybeShowFirstRunNotice, and shutdownTelemetry using
vi.resetModules() and dynamic imports per test so module-level state, status,
and firstRun are reinitialized. Verify the enabled first-run/freebie behavior
and that disabled telemetry paths are no-ops, reusing the existing environment
setup and mocks where needed.
🪄 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: 97e29ac0-3f73-4457-b803-3e488d1cd2f0

📥 Commits

Reviewing files that changed from the base of the PR and between 7752cae and 9048fc6.

📒 Files selected for processing (18)
  • .changeset/cli-anonymous-telemetry.md
  • infra/telemetry-proxy/README.md
  • infra/telemetry-proxy/worker.js
  • infra/telemetry-proxy/wrangler.toml
  • packages/cli/src/__tests__/database-url.test.ts
  • packages/cli/src/bin/main.ts
  • packages/cli/src/cli/registry.ts
  • packages/cli/src/commands/auth/__tests__/region.test.ts
  • packages/cli/src/commands/index.ts
  • packages/cli/src/commands/telemetry/index.ts
  • packages/cli/src/config/tty.ts
  • packages/cli/src/messages.ts
  • packages/cli/src/telemetry/__tests__/state.test.ts
  • packages/cli/src/telemetry/__tests__/telemetry.test.ts
  • packages/cli/src/telemetry/index.ts
  • packages/cli/src/telemetry/state.ts
  • packages/cli/tests/helpers/pty.ts
  • skills/stash-cli/SKILL.md

Comment on lines +48 to +49
const forwarded = new Request(url, request)
forwarded.headers.set('Host', target)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Strip IP-revealing headers to ensure strict anonymity.

When constructing the forwarded request via new Request(url, request), all headers from the incoming request are copied. This includes headers injected by Cloudflare at the edge, such as CF-Connecting-IP and X-Forwarded-For. Even though the CLI uses disableGeoip: true, forwarding these headers exposes the user's raw IP address to PostHog, which undermines the guarantee of anonymous analytics.

Delete these headers from the forwarded request to ensure the telemetry remains fully anonymized at the proxy boundary.

🛡️ Proposed fix to strip IP headers
     const forwarded = new Request(url, request)
     forwarded.headers.set('Host', target)
+
+    // Ensure strict anonymity by stripping IP-revealing headers injected by Cloudflare or intermediaries
+    forwarded.headers.delete('cf-connecting-ip')
+    forwarded.headers.delete('x-forwarded-for')
+    forwarded.headers.delete('x-real-ip')
+    forwarded.headers.delete('true-client-ip')
📝 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
const forwarded = new Request(url, request)
forwarded.headers.set('Host', target)
const forwarded = new Request(url, request)
forwarded.headers.set('Host', target)
// Ensure strict anonymity by stripping IP-revealing headers injected by Cloudflare or intermediaries
forwarded.headers.delete('cf-connecting-ip')
forwarded.headers.delete('x-forwarded-for')
forwarded.headers.delete('x-real-ip')
forwarded.headers.delete('true-client-ip')
🤖 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 `@infra/telemetry-proxy/worker.js` around lines 48 - 49, Update the forwarded
request construction in the proxy handler to remove IP-revealing headers,
including CF-Connecting-IP and X-Forwarded-For, after copying the incoming
request headers and before forwarding to PostHog. Preserve the existing Host
header assignment while ensuring these anonymity-sensitive headers cannot reach
the target.

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