Why Cloudflare Workers Is the Right Runtime for API Key Security
Most API key proxies run on containerised servers - a Node.js process shared across thousands of concurrent requests, with a centralised secrets manager and a single point of failure. Cloudflare Workers' architecture is different in every dimension that matters for security. This article explains why.
V8 isolates: no shared memory between requests
The fundamental property that makes Cloudflare Workers suitable for handling decrypted API keys is the V8 isolate model. Each incoming request executes in a separate V8 isolate - a lightweight, sandboxed JavaScript execution context. Isolates do not share memory with each other.
This is categorically different from how Node.js servers handle concurrency. A Node.js process runs a single event loop and shares heap memory across all concurrent requests. If a decrypted API key is stored in a variable, that variable exists in the shared heap - accessible (in principle) to any code running in the same process, including third-party dependencies or a malicious module introduced through supply-chain compromise.
Node.js process
Cloudflare Worker isolate
For API key proxying, this matters because the decrypted key lives in an isolate that no other customer's code shares. KeyVault Edge decrypts the token per request; the one exception is a small in-memory fallback cache, used only when decryption fails transiently, which lives and dies with the isolate.
Sub-millisecond cold starts vs Lambda latency
Lambda functions and containerised proxies suffer from cold starts - the latency penalty when a new container must be initialised before a request can be served. Cold starts for AWS Lambda range from 50ms to several seconds depending on runtime and memory size. For an API key proxy that adds itself to every outbound API call, that latency tax compounds with every request.
Cloudflare Workers use a different model: isolates are created in under 5 milliseconds and are pre-warmed across Cloudflare's global network. The overhead of a Worker handling a request is typically a few milliseconds for the Worker itself. KeyVault Edge's own work is local Web Crypto (an HMAC check and two AES-GCM decryptions) plus KV and Durable Object lookups for revocation and rate limits. Each proxied response reports the measured overhead in an X-KV-Latency header, and live numbers are on /benchmark.
| Runtime | Cold start p50 | Warm request overhead |
|---|---|---|
| AWS Lambda (Node.js) | 200–800ms | 0–5ms |
| GCP Cloud Run | 500–3000ms | 0–10ms |
| Fly.io (container) | 50–300ms | 0–3ms |
| Cloudflare Workers | <5ms | 0–2ms |
The latency advantage is not just about developer experience - it affects the security architecture. A proxy with high cold-start latency creates pressure to cache decrypted keys across requests. Cheap starts and fast local crypto mean the proxy can decrypt on every request instead.
300+ PoPs: edge execution near every user
Cloudflare operates more than 300 Points of Presence globally. A request from a developer in Singapore, São Paulo, or Warsaw hits a Cloudflare edge node within 20–50ms in almost all cases. The Worker executes at that nearby PoP - not in us-east-1.
For an API key proxy, geographic distribution matters in two ways:
- ▸Latency: The proxy adds latency relative to the client-to-proxy hop, not the client-to-origin hop. If the proxy is co-located with the user (rather than in a single data centre), the latency penalty shrinks from 100–200ms to 5–20ms in most regions.
- ▸DDoS resilience: Cloudflare's network is built to absorb large volumetric attacks. An API key proxy running on Cloudflare inherits that protection.
Centralised proxies (a single region VM or container cluster) create a geography-dependent latency problem and a single-region availability risk. A proxy that is unavailable means API calls fail. The only architecturally sound choice for a proxy that sits in the critical path of every API call is one that is globally distributed by default.
Stateless by default - why that matters for secrets
Workers have no filesystem and no long-lived server process. An isolate can serve many requests and keep module-level variables between them, but it is recycled often and never shared with another customer's code.
That is a useful security property: a long-running server process can accumulate secrets in its heap for weeks, while an isolate's lifetime is short. It is not a guarantee of zero retention, so KeyVault Edge keeps what it holds in memory to a minimum.
The bigger protection is architectural: the master and HMAC keys are encrypted Worker secrets, separate from the database that stores customer data.
What Workers can't do - and why that's fine
Workers have constraints that would be significant for general-purpose server applications but are non-issues for an API key proxy:
CONSTRAINT
CPU time limit (typically 50ms per request)
WHY IT DOESN'T MATTER
HMAC verification, AES-GCM decryption and header injection are a small fraction of that budget. Waiting on the upstream response doesn't count as CPU time.
CONSTRAINT
No direct TCP connections to arbitrary hosts
WHY IT DOESN'T MATTER
Workers use fetch() for all outbound connections, which is sufficient for HTTP/HTTPS proxy forwarding to any upstream API provider.
CONSTRAINT
No filesystem access
WHY IT DOESN'T MATTER
Not needed. Provider keys travel encrypted inside the token; the master and HMAC keys are Worker secrets; revocation and rate-limit state live in KV and Durable Objects.
CONSTRAINT
128MB memory limit per isolate
WHY IT DOESN'T MATTER
A proxy doing AES-GCM decryption and header injection needs very little memory, and responses are streamed rather than buffered.
The constraints that make Workers challenging for complex server applications - no long-running processes, no arbitrary I/O, no large in-memory state - are precisely the properties that make Workers excellent for a security proxy. The architecture forces the exact runtime behaviour you want when handling live API keys.
The full KeyVault Edge architecture on Workers
Here is how KeyVault Edge uses Workers specifically for the proxy flow:
- 1Request arrives at the closest Cloudflare PoP (≤50ms for most of the world). TLS 1.3 terminates at the edge.
- 2Worker reads the kvt_ token from the X-KV-Token header and the provider base URL from X-KV-Target, which must be a public https URL.
- 3Worker verifies the token's HMAC-SHA256 signature with the HMAC key. A tampered or forged token is rejected here and logged as a breach event.
- 4Worker unwraps the token's Data Encryption Key with the master key and decrypts the payload (AES-256-GCM, Web Crypto, no network call). The payload holds the provider key and the token's policy.
- 5Worker checks the request's Origin/Referer against the token's allowed hosts, then its expiry. A mismatch returns 403 and records a breach event.
- 6Worker checks revocation (KV), endpoint scope, rate limits (Durable Object) and the monthly cost cap.
- 7Worker removes the X-KV-* headers, sets the provider's auth header with the real key and forwards the request.
- 8The response streams back to the client unchanged, with X-KV-Edge and X-KV-Latency headers added. Usage is metered off the response path.
Every step before forwarding is local crypto or a lookup on Cloudflare's own storage. See the measured overhead per region on /benchmark.
See the architecture in production
KeyVault Edge is built on exactly the architecture described above. The full encryption flow, memory handling policy, and employee access model are documented publicly.