Skip to content

Security

I found an API key in my page source

The value is served to everyone who views source. Treat it as compromised and rotate it at the provider before fixing how it got there. A build-time prefix such as `NEXT_PUBLIC_` or `VITE_` inlines whatever it is given, which is the usual way this happens. A live sandbox key is the quieter version: the payment form accepts test cards and declines real ones, and nothing is logged as a failure.

What 13x checks

This is rule security.exposed-keys in the public registry: No secret or sandbox keys in the page source. It runs on every audit, against the pages we actually fetched, and its result is derived from the response rather than estimated.

Surface
Security
Score weight
9 of the readiness score
Scope
Runs on every audited page
Applies
To every site

Registry version 2026-07-30. Every rule is published, and the audit is deterministic — the same page produces the same finding every time.

The fix

The same text the audit hands you when this check fails on your own site.

Rotate the key first. It has been served to every visitor and may sit in CDN caches, browser caches and archive copies you do not control. Fixing the code without rotating leaves a working credential in the wild.

1. Revoke and reissue the value in the provider's dashboard. 2. Move it to a server-only environment variable. The rule is simple: if a variable name carries a build-time public prefix, its value is compiled into the JavaScript bundle and shipped.

bash code
# Server-only — never reaches the browser
STRIPE_SECRET_KEY=sk_live_REPLACE_WITH_YOUR_KEY

# Public by design — safe, and the only kind that belongs in client code
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_REPLACE_WITH_YOUR_KEY

3. Read the secret only in server code — a route handler, a server action, or your backend — and never import that module from a client component. 4. Grep the built output before deploying again:

bash code
grep -rE "sk_(live|test)_|AKIA[0-9A-Z]{16}|-----BEGIN" .next/ dist/ build/ 2>/dev/null

If the finding was a test-mode payment key, nothing was leaked — but the checkout is pointed at the sandbox and declines real cards. Swap the publishable key for its live counterpart, and confirm the server's secret key was swapped with it. Mismatched modes fail at charge time, not at page load.

Framework-specific versions

Where the change differs enough to be worth writing out separately.

Does your site have this problem?

13x checks this and 112 others against your live URL in about 30 seconds. No account, and every finding comes with the fix for your framework.

No signup. Results in 30 seconds.

More security checks