A token that can read published content and is meant by its provider for browser use may be acceptable in client code. A token that can read drafts, write content, or manage settings must stay on a server or in the build environment and must never be compiled into the bundle.
Why this goes wrong
Static site frameworks make it easy to expose values to the browser. Next.js documentation states that environment variables with the NEXT_PUBLIC_ prefix are inlined into the JavaScript sent to the browser at build time. That is a feature when the value is a public analytics ID. It is a leak when the value is a content management token with write access.
The failure is quiet. The site works, the build passes, and the token sits in a file anyone can download and search.
Classify every token
Ask three questions for each credential your site uses.
- What can it read? Published entries, or drafts and unpublished entries too?
- What can it change? Nothing, content entries, or configuration and users?
- Can it be restricted by origin, scope or rate, and can it be rotated without downtime?
| Token type | Safe in browser? | Where it belongs |
|---|---|---|
| Published content, read access, provider says public use is intended | Usually yes, with eyes open | Client or build |
| Preview or draft read | No | Server or build, behind authentication |
| Content write or delete | No | Server side |
| Management or admin | No | Never in the site repo or bundle |
| Webhook signing secret | No | Server side verification code |
"Usually yes" still means anyone can copy it and call the API directly, so assume the published data is fully readable and make sure the token is rate limited or scoped.
Steps to check your site today
- Build the site and search the output folder for the token strings, not just their names.
- Search your repository history for the same strings. Removing a token from the latest commit does not remove it from earlier commits.
- List public-prefix variables and review each value one by one.
- Check source maps. If you publish them, they can expose original code that references endpoints and header names.
- Review the provider dashboard for token scopes. Replace any broad token with a narrow one.
- If a write token was ever exposed, rotate it now, then review recent content changes for anything you did not make.
Keep drafts private
Preview features usually need a token, and previews should not be indexed or public. Put preview behind a login or a check on a server, not a client-side flag. See should preview deployments be public.
Build-time access is fine
Fetching content during the build with a server-side token is a normal pattern. The token stays in the CI environment and the output contains just the resulting HTML or JSON. Keep that token in the CI platform's secret store and limit which branches and jobs can use it.
Where Safeguard fits
Safeguard handles dependency and supply chain scanning and policy gates, which helps with the packages around your CMS client. It does not replace a careful review of what gets compiled into your bundle. Free scan: gold.safeguard.sh/scan.
Quick check
Is a read-only token always harmless?
No. If it can read unpublished entries, it exposes drafts. Check its scope, not just its name.
What do I do if a token is already in the bundle?
Rotate it, redeploy, and purge cached copies at the CDN so old bundles stop serving the old value.
Sources
- Next.js documentation, environment variables: https://nextjs.org/docs/app/guides/environment-variables
Last reviewed: 19 October 2026.