Skip to content

fix(security): close P-8 — scrub Bearer/token from _logError before storage#53

Merged
keyxmakerx merged 1 commit into
mainfrom
claude/fm-sec-chunk-4
May 23, 2026
Merged

fix(security): close P-8 — scrub Bearer/token from _logError before storage#53
keyxmakerx merged 1 commit into
mainfrom
claude/fm-sec-chunk-4

Conversation

@keyxmakerx

Copy link
Copy Markdown
Owner

Cites: 2026-05-21-core-tenets §T-B1; reports/foundry/2026-05-22-fm-security-audit.md §2 P-8, §4 Chunk 4, §0.5 D3=(b); dispatches/foundry/FM-SEC-CHUNK-4.md
Security implication: closes P-8 (theoretical Bearer-token / signed-URL-token exfiltration via error log). Without this fix, if Chronicle's error body echoed the request ("Invalid token: Bearer abc..."), the apiKey would land in the in-memory error log surfaced via the dashboard's Status tab.
Consumer-verified: n/a — log-handling change only, no wire surface.
Foundry compatibility: pure JS, ES regex; works across v12/v13/v14.
Mockup: n/a — internal diagnostic; no UI change other than redacted text where a secret would otherwise appear.

What this changes

Adds _scrubAuthHeaders(text) to scripts/api-client.mjs (exported). The helper regex-replaces Bearer <token>Bearer [redacted] and ?token=<value> / &token=<value>?token=[redacted] / &token=[redacted]. _logError calls it on the message before truncation/storage.

9 new behavioral tests in tools/test-api-client-secrets.mjs cover: Bearer redaction, ?token= query-param redaction, mid-query &token=, case-insensitivity, multi-secret messages, non-string input passthrough, and the static-source integration check that pins _logError to call the helper.

Why

The Foundry-side security audit (§2 P-8, §0.5 D3=(b)) flagged the theoretical exfiltration vector. Even with the 200-char truncation in _logError, a 64-char Bearer apiKey fits entirely within the truncation buffer. The scrub closes the leak path without changing the diagnostic value of the log (path + status + non-secret message content still preserved).

Test plan

  • node --test tools/test-*.mjs passes locally (250 baseline + 9 new = 259/259)
  • node tools/check-package-descriptor.mjs passes (descriptor unchanged but ran for hygiene)
  • Tests cover: Bearer redaction, ?token= redaction, &token= redaction, case-insensitivity, multi-secret, non-string, integration
  • Manual verification in Foundry: launch a world; trigger an auth-failed request (e.g., wrong apiKey); open the dashboard Status tab; verify the error-log entry shows Bearer [redacted] instead of the literal token

Tenet self-check

  • T-B1 security: closes P-8 secret-handling finding; defense-in-depth
  • T-B2 plugin isolation: changes stay within chronicle-foundry-module
  • T-B3 production UI: dashboard renders identically except where a secret would otherwise leak
  • T-B4 dual-audience docs: helper has a full doc-comment explaining the threat model; the test file has a long preamble explaining the fix

Stop-and-flag

None encountered. The dropLastErrorLogEntry path (api-client.mjs:609) does NOT return the message externally — only invokes _errorLog.shift() — so no additional scrub needed there. getErrorLog() returns the already-scrubbed entries.


🤖 Cites dispatches/foundry/FM-SEC-CHUNK-4.md. Generated by Claude Code.


Generated by Claude Code

…torage

api-client.mjs::_logError stored Chronicle error response bodies
(truncated to 200 chars) into the in-memory error log surfaced via
the dashboard. If Chronicle's error body echoed the request — e.g.,
"Invalid token: Bearer abc123..." — the apiKey would leak into the
diagnostics panel.

Fix: new _scrubAuthHeaders(text) helper (exported) that regex-replaces
"Bearer <token>" → "Bearer [redacted]" and "?token=<value>" / "&token=
<value>" → "?token=[redacted]" / "&token=[redacted]" before truncation
and storage. Applied at _logError's first line.

9 new tests in tools/test-api-client-secrets.mjs cover behavioral
patterns (Bearer redaction, ?token= query-param redaction, mid-query
&token=, case-insensitivity, multiple-secret messages, non-string
input, integration with _logError).

Test suite: 250 baseline + 9 new = 259/259 pass.

Cites: 2026-05-21-core-tenets §T-B1
       reports/foundry/2026-05-22-fm-security-audit.md §2 P-8, §4 Chunk 4, §0.5 D3=(b)
@keyxmakerx keyxmakerx merged commit 72eee16 into main May 23, 2026
1 check 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.

1 participant