Vulnerabilities
Public JavaScript API Keys vs Server Secrets
May 2, 2025
Public JavaScript API keys vs server secrets is a placement rule, not a naming trick. If a value is in HTML, a bundled .js file, or a public env prefixed for the client, it is public — assume it is copied. Server secrets (database URLs, signing keys, admin tokens, private API keys) belong only on the server. Some vendors issue publishable keys that are meant to be public if they are scoped, rate-limited, and domain-locked. RoastMyOpsec scans inline HTML and same-origin scripts for high-confidence secret patterns; it does not log into your APIs.
The practical difference
A publishable key is designed to identify your project to a vendor from a browser. It should be useless without a server-side counterpart, domain allowlisting, or tight product limits.
A secret key is designed to act as you. If it appears in a client bundle, treat it as stolen until rotated. Minification and 'obscure variable names' are not controls.
How to choose what may ship to the browser
Ask two questions. Can this value create charge, read private data, or admin the product by itself? If yes, it is a server secret. Does the vendor document it as publishable and offer domain restriction? If yes, it may live in the client with monitoring.
| Value | Client? | Why | Takeaway |
|---|---|---|---|
| Publishable payments key | Often yes, if vendor-designed | Cannot capture funds alone when used as documented | Still restrict by domain and monitor |
| Secret / restricted API key | Never | Acts as the account | Rotate if it ever shipped |
| Private PEM / JWT signing key | Never | Mints identity | Incident if it hits git or JS |
| Map or analytics write-only token | Sometimes | Depends on quota and referrer locks | Lock by HTTP referrer and cap usage |
When a 'public' key is still an OPSEC miss
Unscoped cloud keys, webhook secrets, and 'temporary' debug tokens in main.js are not publishable keys. Neither are connection strings with passwords.
If RoastMyOpsec flags a high-confidence pattern, rotate first, then remove it from the bundle and from git history you still control.
Common mistakes
The first mistake is putting NEXT_PUBLIC_ or VITE_ on a secret so the build will 'just work.'
The second mistake is committing .env because a tutorial did.
The third mistake is rotating the key but leaving the old one valid 'for rollback.'
Free audit the URL you own
RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.
Free audit nowFAQ
- Are all API keys in JavaScript vulnerabilities?
- No. Vendor publishable keys are expected in the browser if they are scoped. Unscoped secret keys, PEMs, and database URLs in JS are incident-class.
- Does obfuscating a key in JS protect it?
- No. Anyone can read the downloaded file. Obfuscation is not access control.
- What should I do if a secret shipped in production JS?
- Revoke and rotate it, purge it from the build, check git history, and add a server proxy or a scoped publishable key instead.
Sources
Related guides
Safety
CSP connect-src vs Public JavaScript API KeysVulnerabilities
JSONP vs CORS for Public Browser APIsVulnerabilities
Subresource Integrity vs Unpinned CDN Scripts