Skip to content

fix(oxlint-plugin): allowlist public client keys in no-secrets-in-client-code#612

Merged
rayhanadev merged 2 commits into
mainfrom
ray/caa1d36d
May 31, 2026
Merged

fix(oxlint-plugin): allowlist public client keys in no-secrets-in-client-code#612
rayhanadev merged 2 commits into
mainfrom
ray/caa1d36d

Conversation

@rayhanadev
Copy link
Copy Markdown
Member

@rayhanadev rayhanadev commented May 31, 2026

Why

no-secrets-in-client-code flagged public, client-safe SDK keys (e.g. RevenueCat appl_…) as hardcoded secrets.

These keys are designed to ship in the browser bundle — RevenueCat / Stripe / Supabase / etc. publishable keys carry a type-identifying prefix that is distinct from the vendor's secret key. The rule's variable-name heuristic matches on the variable name (apiKey, token, …) regardless of the value, so an intentionally-public key in a client file was reported as a leak.

Before — reported Possible hardcoded secret in "revenueCatApiKey":

const revenueCatApiKey = "appl_QKLmVFiscBxRYOaeTdZFTulz";

After — no diagnostic (appl_ is a known public client-key prefix):

const revenueCatApiKey = "appl_QKLmVFiscBxRYOaeTdZFTulz";

What changed

  • Added PUBLIC_CLIENT_KEY_PATTERNS to the plugin's security constants (sibling of SECRET_PATTERNS).
  • no-secrets-in-client-code short-circuits before both detectors (variable-name heuristic and secret-shape patterns) when a literal matches a known public prefix.
  • Allowlisted: RevenueCat appl_/goog_/amzn_/strp_, Stripe/Clerk pk_(live|test)_, Supabase sb_publishable_, PostHog phc_, Stytch public-token-(live|test)-, Mapbox pk.eyJ.
  • Still flagged on purpose — ambiguous shapes that can be public or sensitive: Google/Firebase AIza… (same shape as unrestricted server keys) and bare Supabase anon/service_role JWTs (eyJ…, indistinguishable by shape).
  • Adds regression tests: public keys are not flagged; a real sk_test_ secret beside a public key is still flagged.
  • Changeset: react-doctor patch.

Eval results

RDE not run. This change only narrows the rule — it suppresses findings for specific public-key value prefixes and cannot emit new diagnostics — so there is no false-positive surface to sweep; the RDE harness/manifests aren't set up in this worktree. Can run it on request.

Test plan

  • vp test run tests/regressions/no-secrets-in-client-code.test.ts — 31 passed (2 new)
  • pnpm test — 7/7 tasks, 1422 passed
  • pnpm typecheck — 8/8
  • pnpm lint / pnpm format:check — clean
  • pnpm smoke:json-report — OK

Made with Cursor


Note

Low Risk
Narrows lint diagnostics only; does not weaken detection for known secret prefixes or ambiguous Google/Supabase shapes.

Overview
The no-secrets-in-client-code rule no longer reports literals that match known public, browser-shipped key prefixes (RevenueCat appl_/goog_/etc., Stripe/Clerk pk_live_/pk_test_, Supabase sb_publishable_, PostHog phc_, Stytch public-token-, Mapbox pk.eyJ…). A new PUBLIC_CLIENT_KEY_PATTERNS list is checked before both the variable-name heuristic and secret-shape detectors, so names like revenueCatApiKey stop producing false positives when the value is intentionally public.

Ambiguous shapes stay flagged: Google/Firebase AIza… and bare Supabase JWT-style anon/service_role values. Regression tests confirm allowlisted keys are silent and real secrets (e.g. sk_test_) still fire when mixed with public keys.

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

rayhanadev and others added 2 commits May 30, 2026 23:51
…ent-code

Vendor publishable keys (RevenueCat appl_/goog_/amzn_/strp_, Stripe/Clerk
pk_, Supabase sb_publishable_, PostHog phc_, Stytch public-token-, Mapbox
pk.) are designed to ship in the browser, so short-circuit before both
detectors instead of reporting them as hardcoded secrets. Ambiguous shapes
(AIza browser keys, bare Supabase JWTs) stay flagged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment-only: keep the non-obvious rationale (public vs secret prefix,
excluded ambiguous shapes) and drop verbose/duplicated prose. No behavior
change.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings May 31, 2026 06:57
@github-actions
Copy link
Copy Markdown
Contributor

React Doctor

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

Scope: 4 files changed on ray/caa1d36d vs. main.

View workflow run

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 31, 2026

Open in StackBlitz

npm i https://pkg.pr.new/eslint-plugin-react-doctor@612
npm i https://pkg.pr.new/oxlint-plugin-react-doctor@612
npm i https://pkg.pr.new/react-doctor@612

commit: 438dc22

Copy link
Copy Markdown

Copilot AI left a comment

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.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

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 2 additional findings.

Open in Devin Review

@rayhanadev rayhanadev merged commit 3ceb748 into main May 31, 2026
18 of 19 checks passed
@rayhanadev rayhanadev deleted the ray/caa1d36d branch May 31, 2026 07:03
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