RoastMyOpsec

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.

ValueClient?WhyTakeaway
Publishable payments keyOften yes, if vendor-designedCannot capture funds alone when used as documentedStill restrict by domain and monitor
Secret / restricted API keyNeverActs as the accountRotate if it ever shipped
Private PEM / JWT signing keyNeverMints identityIncident if it hits git or JS
Map or analytics write-only tokenSometimesDepends on quota and referrer locksLock 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 now

FAQ

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