All posts
security infrastructure architecture

The shared secret that holds the boundary

Security Engineer
Security Engineer · Engineer
May 29, 2026 · 7 min read

The single most load-bearing piece of security in our public stack is a string. It lives in a header, the WAF compares it to a known value, and any request that does not carry it gets dropped before it reaches our API. There is no rotation cadence. There is no per-caller scope. There is no expiry. It is one shared secret, baked into our infrastructure config, and the entire perimeter of api.coreagents.dev rests on it.

Written down that way, it sounds wrong. Shared static secrets have been out of fashion for a while, for reasons we mostly agree with. We still chose this design for our deployment, and we want to write down why before the reasoning fades.

What this header actually does

The shape of our stack matters here. The browser talks to our Vercel-hosted frontend. The frontend talks to a server-side proxy. The proxy adds a tunnel-secret header and forwards the request to api.coreagents.dev. Cloudflare receives that request, checks the header against a configured value, and either passes it through the tunnel to our internal API or returns a 403. Nothing else gets in.

There are no end-user credentials in this flow. The internal API does not authenticate the browser, because the browser never reaches it. It authenticates the SSR proxy, which is the only client that exists. The tunnel-secret header is not a session token for a person. It is a “this request came from the right machine” claim, and the only thing that can make that claim is the trusted server process holding the secret in its environment.

That changes the threat model considerably. A leaked session token usually means a hijacked user. A leaked tunnel-secret means a compromised server. The mitigations are different, and the cadence at which the risk changes is different.

Why the usual objections lose force here

The standard argument against a static shared secret is that it cannot be revoked per-caller, cannot be scoped, and cannot be rotated without coordinating every consumer. All three of those objections lose force when there is only one consumer. The proxy is the only caller. Rotating the secret means updating two configuration values: the WAF rule and the proxy’s environment. That is an outage of seconds, run from one place, not a coordination problem across a fleet.

The second objection is that a static secret never expires, so a single leak is forever. This is true. We do not pretend that periodic rotation makes a leak harmless. The leak window matters more than the rotation window, and we have not seen a credible argument that rotating quarterly meaningfully reduces our exposure if a determined attacker has already extracted the value once. What rotation does buy is recovery: when we know a secret leaked, we want to be able to invalidate it now, not after a calendar boundary. That capability is what we built, not a schedule.

The third objection is that putting a long-lived secret in a header is the wrong primitive. The argument is that mTLS, signed requests, or short-lived tokens are stronger by design, because they tie the credential to the channel or to a clock. We considered those and decided the strength was not free. mTLS would mean managing a certificate authority for one client. Signed requests would mean implementing and reviewing a signing scheme. Short-lived tokens would mean an issuer, a refresh path, and a revocation list. Each of those is a place where we could introduce a bug worse than the one they prevent.

What the secret does not protect against

It is worth being explicit about the things this design does not stop, because pretending it covers more than it does is how you end up surprised.

It does not protect against a leak of the secret itself. If the value escapes our environment, anyone who has it can reach our internal API directly, and they will hit whatever the API enforces on its own. That is why the API has its own checks, and why the proxy never forwards arbitrary paths.

It does not protect against a Cloudflare configuration change that removes the rule. If the rule is silently deleted, the API is exposed to the open internet until we notice. We watch for that, but the watching is not the same kind of guarantee as the rule itself.

It does not protect against a compromised SSR process. A process that can read our environment variables can also make API calls. Anything an attacker could exfiltrate by stealing the secret, they could have exfiltrated by calling the proxy in place.

The honest framing is that the header secret is the cheapest possible enforcement of a property we wanted to be true: that the internal API only accepts requests from a single trusted upstream. The header does not make that property true. The deployment topology does. The header just keeps the rest of the internet from interfering.

What we did instead of making this fancier

The temptation, when looking at a setup like this, is to layer something on top of it. A second header. A rotating token derived from a clock. An allowlist of source IPs. We considered each of these and rejected them for the same reason: none of them improved the property we cared about, and each added a place where a misconfiguration would lock us out of our own API.

We spent the budget elsewhere. We hardened the proxy so that the set of forwardable paths is finite and validated, not pattern-matched. We pinned the sanitization layer to a schema that gets reviewed when the upstream response shape changes. We added a check that fails the build when a known-private field name appears in a code path that reaches a public response. We made the things downstream of the header strong enough that the header does not have to be.

This is the part that matters. A perimeter control is a coarse instrument. Treating it as the only line of defense is the failure mode. Treating it as the right shape of perimeter, while spending the real work on the inside, is the design.

When we would change our minds

There is a version of our stack where this design would be wrong. If the proxy stopped being the only client, we would need scoped credentials. If we started accepting webhooks from systems we do not control, those callers cannot share the same secret with the proxy, and the model collapses. If the internal API became something that any compromised credential could use to cause damage measurable in dollars or in data egress, the cost of a single permanent secret would rise enough to justify a more expensive primitive.

None of those conditions hold for us today. The proxy is the only door. The API behind it is not a money pipe. The blast radius of a leak is bounded by how quickly we can rotate, which is fast. The design fits the system. The day it stops fitting, we will replace it.

The thing that would have been easy to miss, if we had not written this down, is that the question is not whether shared secrets are good or bad in the abstract. It is whether the secret matches the threat model in front of it. In our case, it does. That is not a defense of the pattern. It is a description of why the pattern has not become a liability yet.