All notes

Worker Secrets Must Not Cross the Browser Boundary

Separate deployment configuration, runtime bindings, public build variables, and credential rotation.

English edition, edited for length. Read the complete Chinese original.

A specific API key was included in the client-side JavaScript code without being committed to the Git repository. This is still a security vulnerability. All resources received by the browser should be treated as public content. The presence of “SECRET” in variable names does not change this principle.

This article assumes that the Worker needs to call third-party services, while the website only accesses the internal API. If a static website doesn’t require server-side functionality, it’s best to avoid adding keys and proxy layers. Unnecessary secrets are the easiest risks to eliminate.

Map Every Execution Environment a Credential Passes Through

A single Astro project might simultaneously involve local development, build processes, worker runtime, and a browser. Build variables and runtime environments do not necessarily share the same API or have the same lifecycle. If a third-party token is only used for a runtime proxy, it should not be placed in the build environment for convenience, and then indirectly read by components. Reducing the number of processes that have access to credentials is more reliable than requiring every call to always be correct.

Calling a third party during the build to retrieve public data is a different requirement. Here the credential is used only to fetch data, and the final output must contain only data approved for public access. Debug fields, user identifiers, or signed URLs returned upstream may be serialized with the original JSON. Convert the response to an explicit DTO on the server before passing it to the page; do not spread the entire upstream object into an island. Hiding the key does not make the returned data private.

Environmental isolation also needs to be applied to permissions. The preview token can read test content, but it does not allow writing to production resources; local credentials can have independent limits and revocation paths. If a third party does not provide fine-grained permissions, operations must be restricted at the proxy layer, while acknowledging that even if upstream credentials are leaked, there is still a significant level of access. Do not use if statements within application code to impersonate the minimum authorization of the credentials themselves.

export default {
  async fetch(request, env) {
    const upstream = await fetch('https://api.example.com/data', {
      headers: { Authorization: `Bearer ${env.API_TOKEN}` },
    });
    if (!upstream.ok) {
      return new Response('Upstream unavailable', { status: 502 });
    }
    return new Response(await upstream.text(), {
      headers: { 'Content-Type': 'application/json' },
    });
  },
};

The example demonstrates only the boundary around reading a runtime binding. Production code must also verify request origins and parameters, limit call rates, and filter returned fields. Hiding the key in the Worker does not prevent endpoint abuse: an anonymous proxy can let attackers consume third-party quota.

Environment variables exposed publicly by Astro are typically included in client-side builds and should not be used to store sensitive server-side credentials. Using secrets during build time also carries risks, such as directly writing the results of server-side calls into HTML or printing request headers in error logs.

Using Configuration Values and Secrets with Different Tools

The following can be included in versioned configurations: public domain names, feature toggles, and resource IDs. Tokens, passwords, and signing keys should be managed using the platform’s secret management system. Local development files must be ignored, and example files should be provided that clearly indicate the required names.

npx wrangler secret put API_TOKEN

Avoid writing secrets in command-line arguments or shell history by using interactive input or controlled CI injection. Different environments should use different credentials, and preview deployments should not have access to production databases or payment permissions. The principle of least privilege should be implemented through third-party accounts, not just documented in the project README.

Administrators of platform accounts can configure secrets, and application code can read and bind to these secrets at runtime. These are distinct sets of permissions. Reducing developer account permissions, protecting deployment tokens, and reviewing production code all fall within the scope of secret management. Even if the platform does not allow direct viewing of previously stored values, individuals with deployment permissions may still be able to deploy code that retrieves and returns these values. Therefore, “the console cannot read” does not mean “the deployer cannot obtain” the values.

During team handovers, document who has the authority to modify bindings, who can deploy, and who can manage upstream tokens. When someone leaves or an account is compromised, these permissions must be revoked, and access should be rotated based on risk. Simply removing someone’s GitHub permissions while retaining their Cloudflare or vendor access creates a backdoor. Personal projects also require protecting machines and accounts; production tokens should not be scattered in chat logs or temporary notes.

The deployment credentials used by CI should be separate from the business credentials used by Workers. The former should be responsible for uploading and configuring, while the latter should be responsible for calling upstream services. Placing administrator tokens in runtime environments to allow applications to “self-manage” would significantly expand the scope of potential damage. In particular, the preview pipeline should not be granted the ability to modify production secrets. Convenience through automation is not a valid reason to compromise environment isolation.

For diagnostics that only need to verify a binding exists, return a boolean and a non-sensitive version identifier. Do not create a management interface to “view all environment variables,” even behind temporary password protection, because it creates a central leakage point. Diagnostic output can be disabled or access-controlled, but the safest design never emits the actual values. Recording necessary state does not require exposing secrets.

Emergency drills can use simulated rollback scenarios in a test environment, using fake credentials to mimic the process: after the old value becomes invalid, the interface returns a controlled error, and then the new value is configured and deployed, restoring the system without any value changes being logged. The drill verifies the permissions, configuration paths, and error handling, without actually interrupting the production environment. Once the necessary steps for recovery are tested, there is no need to guess commands or copy tokens to insecure locations during an incident.

Proxy Endpoints Need Their Own Usage Contract

After placing the upstream token within the Worker, the browser can still call the Worker. If the anonymous endpoint accepts any upstream path and request body, it effectively becomes a public proxy with an account balance. The upstream source, allowed operations, and fields should be fixed, and the request body size should be validated, along with rate and budget limits. The Origin header is not a reliable authentication mechanism, and non-browser clients can directly request it. CORS is also not a permission system for server-side calls.

Business interfaces requiring user authentication must verify the session and determine which resources the user is authorized to access based on their permissions. Public query interfaces must restrict the data that can be accessed publicly and should not return all results from the upstream system solely for the convenience of anonymity. In case of upstream failure, only necessary error categories should be exposed, with detailed diagnostics stored in a controlled log. Do not forward request headers or the complete response body from upstream authentication errors to the browser.

If the upstream address is affected by input, it’s also necessary to prevent SSRF (Server-Side Request Forgery). Using a fixed domain name and a clear routing mapping is more secure than allowing arbitrary URLs; the source after redirection also needs to be considered. Query parameters are generated using a structured API, without concatenating user-provided strings. The boundary between secrets and inputs must coincide at the proxy interface. If either boundary is missing, the conclusion that “the key is not exposed” becomes incomplete.

Rotate Credentials Without a One-Shot Outage

First, create the new credential, configure it in the Worker, and verify that the new version works. Then revoke the old credential. If the provider supports two keys, allow a brief overlap; otherwise, define the maintenance window and recovery path explicitly. Record the key version identifier during the switch, never the value.

When suspecting a leak, simply deleting Git files is not sufficient to address the issue. First, revoke credentials, then check access logs, permission scopes, and unusual usage patterns. While rewriting history can reduce the spread of the compromised data, it cannot guarantee that others have not saved copies of the old content. The primary focus of responding to a secret leak should be on invalidating access.

Assume that the vendor supports two tokens that are simultaneously valid. First, create a new token with the same or narrower permissions, configure the target environment, deploy and run controlled requests, and then observe whether normal traffic uses the new version. Once verified, revoke the old token and then confirm that the old value is indeed invalid. The records include version identifiers and timestamps, but do not store the actual tokens in the rotation document. A brief overlap period requires a limit; you should not indefinitely retain the old key out of concern for rollback.

If a supplier only allows one valid token, it’s necessary to arrange a window for switching, clearly defining the order of obtaining new values, platform configuration, and verification. Rolling back cannot simply restore the previously revoked old values; instead, it’s necessary to prepare for re-issuing or repairing the configuration path. Furthermore, the handling of signing keys should distinguish between the period during which new signatures can be generated and old signatures can be verified, depending on the protocol. It’s important not to directly apply the generic API token rotation process to all key types.

When suspecting a leak, prioritize revoking access to mitigate potential temporary service disruptions. However, continuing to use exposed credentials could exacerbate the damage. The decision should be based on permissions and risk assessment, not delayed by the uncertainty of whether the credentials have been used. Preserve relevant access evidence, confirm the abnormal time period and affected resources, and then restore the service. When a secret appears in Git history, logs, or caches, assume that the copy cannot be completely removed.

Secret Management Records Should Support Recovery and Transfer

Maintain the names, purposes, environments, and access permissions for various entities (e.g., users, applications), along with the responsible personnel and rotation conditions. However, do not maintain the actual values. When a binding is missing at runtime, it should explicitly fail, and should not revert to a hardcoded default token. Also, it should not treat “undefined” as a valid upstream credential and repeatedly retry. Health checks should verify the existence of the configuration, but should not return the values to the checker. When permissions change or personnel leave, revoke the corresponding access based on the defined list, rather than guessing where the tokens were used throughout the codebase.

Vendor quota is another risk boundary. Even legitimate users can quickly exhaust a budget through excessive retries during failures. Set timeouts, limit retries, categorize upstream errors, and never retry authentication failures blindly. Monitoring call volume and cost can reveal proxy abuse, but alerts do not replace endpoint restrictions. Recovery must confirm that the new credential works, the old one no longer works, and the browser cannot access either secret. Rotation is incomplete until all three conditions hold.

Using a Call Chain to Inspect Data and Permissions

The browser submits the article ID, and the worker verifies the current user and identifies the resources they are authorized to access. Then, the worker requests data from a fixed upstream source. Each step should reduce, rather than expand, permissions: the browser cannot choose the upstream URL, the worker does not directly translate user input into account-level operations, and the upstream results are only projected into fields that the user is authorized to read. The key belongs to the server-side, but this call chain determines what the user can do with it.

For example, the upstream may return a complete customer record while the page displays only the public project name. Build the minimum result object in the Worker before serializing it to JSON. Once the complete record reaches the browser, the confidentiality boundary has already been crossed, even if CSS hides the email address. Error responses can likewise contain account IDs, request URLs, or vendor diagnostics. The public endpoint should return only the required error category and correlation ID; private detail belongs in controlled logs with their own redaction checks.

Authentication must be performed using a trusted session or other explicit authentication method, and the Origin header should not be used to identify the user. While CORS restricts browser scripts from accessing the response, non-browser clients can still directly call the endpoint. If a public proxy uses IP-based rate limiting, it must also be aware of the limitations imposed by shared networks and the distribution of access by attackers. Rate limiting controls consumption, authorization controls resources, and budget controls account losses. These three responsibilities cannot be replaced by each other.

Tests should use two synthetic users and two resource sets to confirm that user A cannot use the proxy to read user B’s data. They should also try unknown upstream paths, oversized requests, and disallowed fields, confirming that rejection happens before any upstream call. A test upstream can record call counts and synthetic parameters to prove that rejected requests consume no third-party operations. Do not query real user data to verify isolation; synthetic data is sufficient to cover the business boundary.

Treating Credential Rotation as a Version Compatibility Issue

When a vendor allows dual token usage, both the new and old Worker versions may run concurrently during the transition. Whether the old version can still read the old binding depends on the platform configuration and the version model. It’s not safe to assume that deploying a new value will automatically cause all old instances to switch over. The migration plan needs to verify the actual platform behavior and determine when to revoke the old token to balance risk and availability. The version number records the usage relationship, but does not store the actual secret.

The requirements for signature keys and API tokens are different. API tokens are typically used for outgoing requests, while signature keys also involve validating older tokens. A new signature can be immediately used with the new key, while validating an older signature may require a limited compatibility window and key identification. The protocol should support secure key selection, and should not read files or dynamically obtain unauthorized keys based on any user input. The maximum lifespan of an old signature is determined by the compatibility window, not by the practice of “cleaning up later” by the maintainer.

If a new credential proves too restrictive during rotation, identify the operations the service actually needs instead of restoring administrator access. Test that allowed operations succeed, prohibited operations fail, and the old credential stops working after revocation. A successful health endpoint alone does not prove that real business operations have the permissions they need. Observe authentication errors and quota changes, but do not copy the provider’s entire diagnostic response into a public report.

When a leak is suspected, compatible windows may need to be shortened or immediately closed. The recovery process will not be identical to normal rotation, as continuing to hold old tokens would still allow attackers to use them. Prioritize risk isolation, then restore limited functionality, and inform users which operations are temporarily unavailable. A compromised credential that is still available is not a rollback asset and should not be enabled to continue with a 200 response.

Conducting Secret Reviews for Development Tools and Dependencies

The secret is not stored within the client, but may be present in development tool caches, exception tracking attachments, or test snapshots. Passing the complete env object to a generic debugging function makes it easy for layers outside the business code to access it. Review the automatic capture configurations of unified logging middleware, error handlers, and telemetry SDKs, using a field whitelist instead of simply removing Authorization in a single interface.

When local tools require secrets, use development credentials with restricted permissions and avoid automatically copying production configurations in project scripts. Ensure that plugins, package installation scripts, and third-party CLI run in processes that can access the environment, and be aware that this also expands the set of code that has access to secrets. CI can separate the retrieval, build, and deployment stages, and inject the corresponding credentials only in the required stages. While isolating stages cannot eliminate all supply chain risks, it reduces the opportunity for unrelated tools to gain access.

The test snapshots should use clearly falsified values that can check for de-identification without creating copies of real credentials. If the scan detects real values, the report should identify the file and type, and the full content should not be reprinted on the terminal. Temporary files should also be subject to cleanup and permission management, to prevent configuration backups from being placed in publicly accessible output directories. The file Git should not control the permissions of other processes on the local machine, nor should it control which directories deployment tools scan.

Derive Proxy Resource Budgets from Account Quotas

While anonymous query interfaces may not result in data leaks, attackers can consume vendor credits. First, determine the maximum number of upstream calls that each legitimate task can trigger, which failures are allowed to retry, and the upper limit for retries. Authentication failures should not result in continuous retries, and timeouts do not necessarily mean that the upstream call has not been executed. For operations that incur costs or have side effects, query results or use vendor-supported idempotent mechanisms should be used. Do not treat limited retries as a complete solution for repeated charges.

Establish different observation dimensions for the overall budget and per-user consumption. Restrictions on shared IP addresses may affect legitimate users, while user-level budgets can protect against overall losses. Instead of indefinitely queuing all requests, provide clear status when the budget is reached. Alerts should be triggered before the limit is exhausted, but the thresholds should be based on the actual capabilities of the account and business needs, not a fixed number. Record the types of anomalies and credential versions to help determine whether a public proxy is being abused, code retries are causing issues, or there is a vendor failure.

After restoration, verify the following three aspects:

  1. New credentials only grant the expected permissions.
  2. Old credentials have been invalidated.
  3. The browser and downloadable output do not contain secrets.

Additionally, confirm that budget protection and error handling are still functioning correctly. The key rotation solution addresses the lifecycle of exposed values, input restrictions, and resource budget limitations, ensuring that the agent remains in use within the defined scope. Maintaining both aspects together is crucial to prevent similar incidents in the future.

Check both the product and the logs

After building, verify that the HTML, JS, source maps, and configuration outputs do not contain any key names or test markers. Use dedicated placeholder values for testing, and do not print real keys to the terminal or CI output for the purpose of searching. While security scanning can supplement the check, it cannot identify all business credentials.

Logs also need to be audited: Do not record complete requests, all authentication information from environment variables or third-party responses, or sensitive context. Errors should include a correlating ID and non-sensitive context. When upstream tests fail, public responses should not expose tokens, internal addresses, or stack traces.

Acceptance isn’t just about the API returning a 200 status code. It also includes: no third-party credentials in the browser’s network requests, limited preview environment permissions, the new version functioning correctly after revoking an old token, and unauthorized calls being restricted. The key challenge in secret management is throughout the entire lifecycle, not just renaming a field to “Secret”.

The scanning process should also cover the reversible transformation of credentials. A debugger might inject a fake token into a URL-encoded query, while another might serialize the authentication fields into Base64. If the original value search fails, it doesn’t necessarily mean that the value wasn’t delivered. By independently traversing these two synthetic paths using unique fake values, confirm that the test can identify the transformations in the output. Avoid writing real tokens and their encodings in bulk into the scanning rule file to cover more formats, as this would create new secret copies.

Not all credential-based tokens share the same risk profile as the original token. Short-lived signature download addresses created on the server may not contain the original token, but still grant a specific object access. The verifier should not only look for the API_TOKEN; it must also list which return fields represent permissions, as well as the scope, validity, and transferability of those fields. If a publicly accessible page receives an unauthorized signature address, even without a third-party key, the security boundaries remain compromised.

The acceptance process allows users without authorization to attempt obtaining a controlled object address, confirming that the denial occurs before signing. Once the user has obtained the address, the protocol then checks for expiration and object scope. If the service cannot revoke previously issued signing capabilities, it accurately records the remaining window, rather than claiming that automatic rotation of API tokens automatically revokes all derived links. The original credentials remain secure, and derived authorizations do not exceed their scope, which are two separate results that must be independently verified.

References: Workers Secrets, Astro Environment Variables.