fix(redact): catch product-native credentials in content-shaped secret detection - #33
Conversation
…t detection Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new Box token prefix regex may miss valid box_ tokens that don’t include a qualifier segment, leaving a potential standalone-secret leak path.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR strengthens server/redact.ts’s “content-shaped secret” detection by expanding KEY_PREFIXES to include two HelmRyth-native credential formats that can appear as standalone text (e.g., in tool titles, bot replies, permission cards), ensuring they’re masked even when key-name heuristics don’t apply.
Changes:
- Added
box_*andwhsec_*prefix-based regexes toKEY_PREFIXESfor content-shaped secret redaction. - Added corresponding test cases in
server/redact.test.tsto verify masking behavior.
File summaries
| File | Description |
|---|---|
| server/redact.ts | Extends prefix-based redaction patterns to catch Box tokens and webhook secrets in plain text. |
| server/redact.test.ts | Adds regression cases ensuring the new prefixes are masked when embedded in text. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| /\bAKIA[0-9A-Z]{16}\b/g, // aws access key id | ||
| /\bAIza[0-9A-Za-z_-]{30,}/g, // google api key | ||
| /\bnpm_[A-Za-z0-9]{20,}/g, // npm | ||
| /\bbox_[a-z]+_[A-Za-z0-9_-]{4,}/g, // ascii.dev box api token |
|
@DevChiniwala — the insight behind this one is the best of the three. The redactor covered third-party credentials while missing the two this product mints and accepts itself. That's a gap you only find by reading the codebase properly, and "product-native" is exactly the right framing. I confirmed the gap is real. On The existing
|
| value | current | box_[A-Za-z0-9_-]{16,} |
|---|---|---|
box_live_abcdefghijklmnop (your fixture) |
MATCH | MATCH |
box_ + mixed-case payload, no word segment |
MISS | MATCH |
box_live_zzz (repo fixture) |
MISS (payload is 3, needs 4) | — |
box_shadow_none |
MATCH | — |
box_model_border |
MATCH | — |
box_sizing_content |
MATCH | — |
So it misses real keys and redacts ordinary identifiers. The false positives are the more serious half, because they contradict the contract stated directly above your change:
High precision on purpose: a generic "long hex/base64" heuristic would rewrite real code in the transcript, so only shapes that are unmistakably credentials match.
The test passes because it asserts the one shape the regex was built around — worth watching for, since a green test on a guessed format reads as more assurance than it is.
Requested change
/\bbox_[A-Za-z0-9_-]{16,}/g, // ascii.dev box api tokenFollows the rule box.ts actually states, catches payloads regardless of case or structure, and the {16,} floor clears box_shadow_none, box_model_border and box_sizing_content — all of which fall short of it.
I checked this doesn't regress anything: box_live_zzz and box_live_dontlogme are both redacted via the env-key path, not this one, so shortening coverage here changes no existing test.
One coordination note
This and #32 both insert after the npm_ line in server/redact.ts and at the same spot in server/redact.test.ts. I confirmed they conflict — whichever lands first, the other needs a rebase.
CI hasn't run yet; GitHub holds workflow runs for first-time contributors until a maintainer approves. I'll approve it.
Swap the box_ pattern and this is a good change. Thanks for digging into the actual credential surface rather than just adding well-known prefixes — that's the harder and more useful version of this work.
Summary
KEY_PREFIXESinserver/redact.tscatches content-shaped secrets — credentials that appear as standalone text in bot replies, tool titles, and permission cards, where the key-name heuristic (isSecretName) does not apply.Two credential prefixes native to HelmRyth itself were missing:
box_*— ascii.dev Box API tokens (box.ts:195validatestoken.startsWith("box_")). A leaked token grants access to the user's cloud computers.whsec_*— webhook signing secrets (webhooks.ts:280generates"whsec_" + randomBytes(32)). A leaked secret allows unauthenticated webhook delivery.Both are caught when they appear inside key-value structures (the key name contains "token" / "secret"), but pass through unmasked as standalone text — a bot echoing a curl command, a user pasting a token into chat, or a tool output containing the raw value.
What changed
KEY_PREFIXES, positioned betweennpm_and JWT. Thebox_pattern requires a qualifier segment (box_live_,box_test_, etc.) to avoid matching variable names likebox_model.Verification
pnpm typecheck— cleanpnpm test -- server/redact.test.ts— all 13 tests passpnpm check:brand— clean