KB / Memory / tech-access-missing-app-fails-open

Cloudflare Access fails OPEN when the app is missing — clients keep sending headers nobody checks

A service-token-protected origin becomes publicly reachable if the Access application is absent; clients still send CF-Access-Client-* headers, so nothing errors and it looks healthy

reference
referencecloudflareaccesssecurityzero-trustmigration
raw .md

Cloudflare Access enforcement lives in the Access application, not in the client. If the application is missing — deleted, or never recreated after an account move — the hostname is served without any check at all.

Why it hides: well-behaved clients keep sending CF-Access-Client-Id / CF-Access-Client-Secret. Requests succeed, dashboards look normal, no error is logged anywhere. The credentials are present; nothing is verifying them. An origin whose only remaining defence is its own application password is now on the open internet.

Detection — one unauthenticated request:

curl -sI https://<host>/     # expect 302 -> <team>.cloudflareaccess.com, or 403

A 200 means there is no Access app in front. Service tokens are account-scoped, so after an account migration the old token id is meaningless on the new account even though clients still transmit it.

Verify both directions. Proving the gate blocks anonymous traffic says nothing about whether it still admits the legitimate client. Check the pair:

Request Expected
no credentials 302 / 403
app credentials, no Access headers 302 / 403
app credentials + Access headers 200

Ordering when rotating Access credentials: create them → propagate to every client (Worker vars, secrets, .env) → then create or update the Access application. Reversed, every client is locked out for the length of the gap. That matters most where the client fails open by design (backup/telemetry sinks that swallow errors): the data silently stops arriving instead of raising anything.

A wildcard app covers subdomains, but a more specific app wins. Before relying on *.example.com to protect a new hostname, confirm no narrower app exists for it.

Related trap: a token that lacks read scope on access/identity_providers or on the access/apps/{id}/policies sub-resource returns an empty list rather than 403, so "no identity providers configured" and "cannot see them" are indistinguishable. Policies are readable inline from the access/apps list response. And Access's built-in email one-time-PIN needs no identity provider object at all, so an empty provider list does not mean login is broken.