How workerd Handles Cross-Origin Requests: Server-Side Fetch Without Browser CORS Enforcement

workerd handles cross-origin requests by forwarding them directly to the upstream server without performing browser-style CORS validation, only stripping the Authorization header on cross-origin redirects when the StripAuthorizationOnCrossOriginRedirect compatibility flag is enabled.

Unlike browsers that enforce strict Cross-Origin Resource Sharing (CORS) policies, the Cloudflare workerd runtime implements a server-side Fetch API that leaves CORS validation to the upstream server or the worker script itself. Understanding this behavior is critical for developers building edge functions that interact with third-party APIs, as workerd does not automatically block requests based on origin mismatches or generate preflight responses.

No Built-In CORS Preflight or Mode Enforcement

The workerd runtime does not implement the CORS protocol as specified for web browsers. When you create a Request object in workerd, several CORS-related fields are explicitly marked as unimplemented in the source code, including mode, credentials, referrer, and referrerPolicy.

In src/workerd/api/http.c++, the Request constructor notes these limitations:

// src/workerd/api/http.c++ – Request constructor notes
// .mode is unimplemented
// .credentials is unimplemented
// .referrer is unimplemented
// .referrerPolicy is unimplemented

Because these fields are ignored, setting mode: 'cors' or credentials: 'include' has no effect on the request execution. The runtime forwards the HTTP request exactly as specified—including all headers, methods, and body content—without checking Origin headers or validating Access-Control-Allow-Origin responses. Any CORS validation must be performed by the upstream server or manually implemented within the worker script.

Authorization Header Stripping on Cross-Origin Redirects

The only automatic cross-origin handling workerd provides involves redirect behavior. When the stripAuthorizationOnCrossOriginRedirect feature flag is enabled, the runtime removes the Authorization header when following a redirect to a different origin. This implements the Fetch specification's rule for "CORS non-wildcard request-header names," which currently applies only to the Authorization header.

The redirect handling logic in src/workerd/api/http.c++ (lines 1764–1788) implements this check:

// src/workerd/api/http.c++ – redirect handling
if (FeatureFlags::get(js).getStripAuthorizationOnCrossOriginRedirect()) {
  auto base   = urlList.back().toString();
  auto cur    = JSG_REQUIRE_NONNULL(jsg::Url::tryParse(base.asPtr()), TypeError,
                                   "Invalid current URL; unable to follow redirect.");
  auto loc    = JSG_REQUIRE_NONNULL(jsg::Url::tryParse(location, base.asPtr()), TypeError,
                                   "Invalid Location header; unable to follow redirect.");
  if (cur.getOrigin() != loc.getOrigin()) {
    // Delete the only CORS‑non‑wildcard request‑header name: "Authorization"
    jsRequest->getHeaders(js)->deleteCommon(capnp::CommonHeaderName::AUTHORIZATION);
  }
}

This security measure prevents accidental credential leakage when an upstream server redirects to an unexpected third-party domain. The feature is controlled through compatibility flags defined in src/workerd/io/features.h and configured via src/workerd/io/compatibility-date.capnp.

Practical Implementation Examples

Basic Cross-Origin Fetch Without CORS Enforcement

When fetching resources from different origins, workerd sends the request without modification:

// worker.js – simple cross-origin fetch
export default {
  async fetch(request, env) {
    // No `mode` support – the request is sent as‑is.
    const resp = await fetch('https://api.example.com/data', {
      headers: { Authorization: 'Bearer secret' },
    });
    // The response is returned unchanged.
    return resp;
  },
};

If the upstream server redirects to a different origin and the StripAuthorizationOnCrossOriginRedirect flag is active, the Authorization header is automatically removed before following the redirect.

Enabling the Strip-Auth Feature Flag

To activate the authorization stripping behavior, add the compatibility flag to your worker configuration:


# workerd config (worker.toml)

[[services]]
name = "my-worker"
worker = { modules = [{ name = "worker", esModule = embed "worker.js" }] }

[[services.compatibility_flags]]

# Enable stripping Authorization on cross‑origin redirects

"StripAuthorizationOnCrossOriginRedirect"

With this configuration enabled, any cross-origin redirect will have the Authorization header removed before the subsequent request is dispatched.

Manually Implementing CORS in Worker Scripts

Since workerd does not add CORS response headers automatically, you must implement CORS handling explicitly when serving browser clients:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    // Handle preflight OPTIONS requests
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
          'Access-Control-Allow-Headers': 'Authorization, Content-Type',
        },
      });
    }
    
    const resp = await fetch(url);
    const newResp = new Response(resp.body, resp);
    newResp.headers.set('Access-Control-Allow-Origin', '*');
    return newResp;
  },
};

This pattern allows full control over CORS policies while leveraging workerd's server-side fetch capabilities.

Key Source Files for Cross-Origin Handling

Understanding the implementation requires examining these specific files in the cloudflare/workerd repository:

  • src/workerd/api/http.c++: Contains the core Fetch implementation, redirect handling logic, and feature-flag checks for header stripping.
  • src/workerd/io/features.h: Declares the FeatureFlags structure, including the stripAuthorizationOnCrossOriginRedirect flag.
  • src/workerd/io/compatibility-date.capnp: Lists available compatibility flags that control runtime behavior.
  • src/wpt/fetch/api-test.ts: Web Platform Tests that verify Fetch behavior, including CORS-related expectations.

Summary

  • workerd does not enforce browser CORS rules: The runtime forwards cross-origin requests exactly as specified, ignoring mode and credentials options.
  • Authorization stripping is opt-in: The only automatic cross-origin handling is the removal of the Authorization header on cross-origin redirects when the StripAuthorizationOnCrossOriginRedirect compatibility flag is enabled.
  • No preflight generation: OPTIONS requests are treated as standard HTTP requests; workerd does not generate or validate CORS preflight responses.
  • Manual CORS implementation required: Developers must add Access-Control-Allow-Origin and related headers manually when serving browser-based clients.

Frequently Asked Questions

Does workerd block cross-origin requests by default?

No, workerd does not block cross-origin requests. Unlike browsers, which enforce same-origin policies and require CORS headers to permit cross-origin access, workerd forwards requests to any origin without validation. The runtime operates as a server-side environment, leaving origin-based access control to the upstream server or the worker script's logic.

Why does my Authorization header disappear on redirects?

If your Authorization header is missing after a redirect, the StripAuthorizationOnCrossOriginRedirect compatibility flag is likely enabled in your deployment. This feature automatically removes the Authorization header when a redirect crosses origin boundaries to prevent credential leakage to unintended domains. Check your compatibility flags in src/workerd/io/compatibility-date.capnp or your runtime configuration.

How do I enable CORS for browser clients in workerd?

You must manually implement CORS handling by inspecting incoming requests and setting appropriate response headers. For OPTIONS preflight requests, return a response with Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers headers. For actual requests, copy these headers onto the response before returning it to the client.

What happens if I set mode: 'cors' in a fetch call?

The mode property is currently unimplemented in workerd according to src/workerd/api/http.c++. Setting mode: 'cors' or any other mode value has no effect on the request execution. The runtime sends the request exactly as configured without performing CORS checks or modifying headers based on the mode setting.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →