Skip to content

fix(core): redact secrets and PII from diagnostic output - #600

Closed
rayhanadev wants to merge 1 commit into
mainfrom
fix/redact-secrets-from-diagnostics
Closed

fix(core): redact secrets and PII from diagnostic output#600
rayhanadev wants to merge 1 commit into
mainfrom
fix/redact-secrets-from-diagnostics

Conversation

@rayhanadev

@rayhanadev rayhanadev commented May 30, 2026

Copy link
Copy Markdown
Member

Summary

Closes the privacy gap behind #598. react-doctor's diagnostic message/help strings can embed fragments of the user's source (e.g. string literals echoed via stringifyExpressionSnippet in rules like no-initialize-state). Those strings are printed to the terminal, written to the --json report, and POSTed to the score API (https://www.react.doctor/api/score) by default. So a hardcoded API key, token, connection string, or email in someone's code could be echoed locally and transmitted off-machine.

This adds a high-precision redactor and applies it at cleanDiagnosticMessage in parse-output.ts — the single point every diagnostic flows through — so the terminal, the JSON report, and the score upload all share the same scrubbed text. react-doctor should never echo or transmit a user's secrets, even locally (CI logs, screen shares, pasted output).

What gets redacted (→ <redacted>)

  • Known credential formats: AWS access keys, GitHub tokens (ghp_/gho_/github_pat_), GitLab (glpat-), Slack (xox…), Stripe (sk_live_/pk_live_…), OpenAI (sk-…), Google (AIza…/ya29.…)
  • PEM private key blocks and JWTs
  • Credentials inside URLs (scheme://user:pass@hostscheme://<redacted>@host, host kept)
  • Bearer <token> (keyword kept, token masked)
  • Email addresses (PII)
  • Unprefixed high-entropy tokens (≥32 base64url/hex chars containing both a letter and a digit)

Patterns are intentionally narrow — ordinary identifiers, short captions, and line:column noise are left untouched, so normal diagnostics stay readable.

Why redact instead of strip the fields

Investigated the server side in react-review: scoring (summarizeScore, calculateDoctorScore) and analytics (Axiom) only use plugin/rule/severity — never message/help. But the doctor-CLI ingest does persist message/help to S3 and render them in the dashboard's diagnostics list. Stripping the fields would have required a coordinated, deploy-ordered server schema change and would have gutted the dashboard. Redacting keeps the fields valid and useful while removing the sensitive content, in one repo, with no server coordination.

Test plan

  • pnpm typecheck
  • pnpm test — 1418 pass; the only failure is the pre-existing environmental unref-stdin-live TTY probe (unrelated to these files)
  • pnpm lint
  • pnpm format:check
  • pnpm smoke:json-report
  • 15 new unit tests in packages/core/tests/redact-sensitive-text.test.ts covering each detector, false-positive guards, and idempotency

Made with Cursor


Note

Medium Risk
Security-sensitive output path with regex heuristics that could over-redact rare long tokens, but scope is limited to diagnostic text and is well tested.

Overview
Adds redactSensitiveText and runs it on every diagnostic message / help in cleanDiagnosticMessage (oxlint parse path), so echoed source literals cannot leak API keys, tokens, JWTs, PEM keys, credentialed URLs, Bearer values, emails, or long high-entropy strings to the terminal, --json, or the score API.

Detectors are ordered (structured secrets first, then a ≥32-char generic token sweep with letter+digit guards) and replace matches with <redacted> while keeping normal diagnostic prose readable. GENERIC_SECRET_MIN_LENGTH_CHARS is exported from core; the helper is re-exported from @react-doctor/core, with unit tests covering each pattern, false positives, and idempotency. Patch changeset included.

Reviewed by Cursor Bugbot for commit 9f52803. Bugbot is set up for automated code reviews on this repo. Configure here.

Diagnostic messages can embed source fragments (e.g. string literals via
stringifyExpressionSnippet), so a hardcoded API key, token, or email in a
user's code could be echoed to the terminal / JSON report and POSTed to
the score API. Scrub message/help in cleanDiagnosticMessage — the single
point every diagnostic flows through — using a high-precision detector for
known credential formats, credentialed URLs, private keys, JWTs, emails,
and unprefixed high-entropy tokens. Local output and the upload now share
the same scrubbed text.

Addresses #598.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings May 30, 2026 20:54
@github-actions

Copy link
Copy Markdown
Contributor

React Doctor

React Doctor found 6 files changed in this pull request, but none matched the files covered by its enabled checks.

Scope: 6 files changed on fix/redact-secrets-from-diagnostics vs. main.

View workflow run

Generated by React Doctor. Questions? Contact founders@million.dev.

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@devin-ai-integration devin-ai-integration Bot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@rayhanadev rayhanadev closed this May 30, 2026
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