Skip to content

fix: redact interpolated secrets from telemetry and experience files (plan 003)#71

Open
DavertMik wants to merge 3 commits into
mainfrom
fix/redact-interpolated-secrets
Open

fix: redact interpolated secrets from telemetry and experience files (plan 003)#71
DavertMik wants to merge 3 commits into
mainfrom
fix/redact-interpolated-secrets

Conversation

@DavertMik

Copy link
Copy Markdown
Contributor

Implements plan 003 (plans/003-redact-secrets-from-persistence-and-telemetry.md) — a P1 security fix.

Problem

Knowledge files interpolate ${env.APP_PASSWORD} (and other ${env.*} / ${config.*}) into cleartext at load time. Those resolved secrets then flow into two persisted/exported sinks:

  • Langfuse trace input (JSON.stringify(metadata.input) shipped to telemetry).
  • On-disk experience files — which are routinely git-committed (the repo ships example/experience/*).

Separately, ${config.*} walked the entire config object and stringified any leaf, so ${config.ai.apiKey} silently expanded the provider API key into every prompt and both sinks.

Fix

  • New src/utils/secrets.ts: a process-global secret registry (registerSecret), redactSecrets(text), isSecretName(name) (credential-name denylist), and clearRegisteredSecrets() for test isolation.
  • knowledge-tracker.ts: the env branch registers credential-named values (still returns cleartext — the model must type the real password), and the config branch blocks credential-named keys from interpolating at all (SEC-03).
  • observability.ts + experience-tracker.ts: run redactSecrets on the serialized telemetry string and on experience content before write. Both are single chokepoints.

Verification

  • bun test tests/unit/secrets.test.ts tests/unit/knowledge-tracker.test.ts → 15 pass (incl. ${config.ai.apiKey} blocked, and ${env.APP_PASSWORD} register→redact end-to-end)
  • bun test tests/unit → 736 pass, 0 fail; bun run lint clean

Deferred (intentional — see plan Maintenance notes)

Masking the credential in (a) the LLM request itself (needs CodeceptJS secret() + a prompt change), (b) the AI SDK's experimental_telemetry inputs, and (c) the Testomat.io reporter. This PR is not a complete secret-masking solution — it closes the two persisted/exported sinks we control.

🤖 Generated with Claude Code

Knowledge files interpolate ${env.SECRET} into cleartext at load time; those
resolved values flowed into two persisted/exported sinks — the Langfuse trace
input and on-disk (often git-committed) experience files. Separately,
${config.*} could expand credential leaves like ${config.ai.apiKey} into every
prompt and both sinks.

Add src/utils/secrets.ts (a process-global secret registry + redactSecrets).
The env interpolation branch registers credential-named values (still returning
cleartext, since the model must type the real password) and both sinks now run
redactSecrets on the serialized/content string. Credential-named ${config.*}
paths are blocked from interpolating at all.

Deferred (see plan 003 Maintenance notes): masking in the LLM request itself,
the AI SDK experimental_telemetry inputs, and the Testomat.io reporter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown

Explorbot Self-Regression

Commit 6558578 · run

Scenario Result Attempts Duration
basic (native) PASS 1/3 10m
experience: control OK — failed as expected 1/1 3m
experience: seeded PASS 1/3 1m

Attempt details

  • basic (native) Feat/researcher improvement #1 — PASS: login evidence: PASS (post-login plan=true, post-login research=true); research: PASS (files=7, wellFormed=true, keywords=7/3); scenarios: PASS (tests=6/5, features=4/3); tests passed: PASS (4 passed, 0 failed (reporter: 4 passed, 0 failed))
  • experience: control Feat/researcher improvement #1 — PASS: control: OK — failed as expected (0 passed, 1 failed)
  • experience: seeded Feat/researcher improvement #1 — PASS: seeded: PASS (1 passed, 0 failed)

Session analysis — basic (native):

Session Analysis

The issue tracking system core flows are operational: creating issues with labels, viewing issue details, keyword search, and filter reset all work correctly. The test suite completed with all scenarios passing.

Coverage

  • Pages: /issues, /issues/:id
  • Features: Issue creation, detail navigation, keyword search, label filtering

What works

  • Issue creation with labelsET-1 Create new issue with label and verify it appears in list
  • Issue detail viewET-2 Open issue detail from list and verify content displays
  • Keyword searchET-3 Search issues by keyword and verify matching results
  • Label filter resetET-4 Reset label filter and verify all issues display

Execution Issues

  • ET-1 — form fill initially failed then succeeded on retry, requires investigation into initial interaction failure

DavertMik and others added 2 commits July 11, 2026 16:29
Per re-review: iterate registered secrets longest-first in redactSecrets so a
secret that is a substring of another no longer leaves a partial-secret fragment
(genuine hardening for a security fix). Group SECRET_NAME_TOKENS with the other
module consts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant