Classify values by authority
Create a short list of public configuration: API base URLs, public product identifiers and nonprivileged feature labels can legitimately reach the browser. Keep database credentials, signing keys, provider secrets and privileged service tokens in server-controlled storage.
A value is not safe merely because it looks random or is called a key. Determine what possession permits. Some public integration identifiers are designed for browser use with separate server rules; a credential that authorizes billing or private data access requires a different boundary.
Trace the build substitution
Vite exposes variables with its configured public prefix, commonly VITE_, to client code. Other frameworks have their own mechanisms. Check the exact bundler and framework settings in use, including custom define replacements and plugins that serialize a broad environment object.
Avoid passing all process.env values to the client for convenience. Use an explicit allowlist of public configuration fields. Review HTML templates and generated config.js files too: a secret can escape through a template even if no TypeScript module imports it.
Review the release with synthetic values
In an isolated nonproduction build, use recognizable harmless sentinels for public and private settings. Search the completed output for those sentinels and confirm that only deliberately public values appear. Do not paste real production secrets into terminal output, issues or benchmark fixtures.
Then audit the actual deployable tree for known credential patterns and sensitive companion files. CloneGuard can identify some exposures and redact matching values in findings, but pattern screening cannot classify every organization-specific credential or prove the absence of all secrets.
Handle a real exposure as a credential event
If a privileged credential has been delivered to browsers, removing it from the next bundle is only one containment step. Revoke or rotate it through the provider, investigate authorized logs and scope, and account for old CDN versions or cached downloads. Follow your organization’s response process.
Move the privileged operation behind authenticated server authorization and publish a new artifact. Validate both the successful user workflow and denied direct requests. The lasting correction is a smaller trust boundary, rather than a new name for the same client-side secret.
Review authority with a simple example
Suppose the browser needs to select an upload region and request an upload. A public region label and API endpoint can be appropriate configuration. A storage account credential that can list or replace arbitrary objects is not. Send the upload request to an authenticated server operation, authorize its scope, and return a restricted upload capability if the platform supports it. Test the denied case as well as the happy path. Merely changing VITE_STORAGE_SECRET to STORAGE_SECRET does not prove the original value stopped reaching a custom config serializer or an HTML template.
Practical checklist
- Maintain an explicit public-configuration allowlist.
- Inspect template injection and plugin replacements.
- Use synthetic sentinels for build tests.
- Rotate real exposed credentials and review old cached assets.
Sources and further reading
Primary references support the technical details. Procedures here are guidance; only explicitly recorded project results describe tests we ran.
Prepared with AI assistance. How this library is produced. Suggest a correction; keep private code and credentials out of public issues.