An empty list switches its check off. A Theme nobody has configured restricts nothing.
Origin allowlist
List the origins allowed to fetch the Theme:Origin header. If there is no Origin, it falls back to Referer.
Origin wins over Referer when both are present. Origin is the browser’s statement of who
is asking; a Referer can name a page the request merely passed through.A sandboxed frame sends the literal string null as its origin. That is refused, not treated
as missing — otherwise a sandboxed page on any site could take the missing-origin path below.Requests that name no origin
This is the case that catches people. A<link rel="stylesheet"> without crossorigin sends no
Origin header — the only signal is Referer, and a page with Referrer-Policy: no-referrer
withholds that too. A server-side render, a build step or a curl sends neither.
So the Theme chooses:
“Looks like a browser” means it carried a
Sec-Fetch-* header — every current engine sends them and
no page script can set them. So a browser page that stripped its referrer is refused, while your
server fetching at render time is let through.
Browsers too old to send
Sec-Fetch-* (Safari before 16.4) are indistinguishable from servers and
pass. This setting is ignored entirely when the Theme lists no origins — with no allowlist there is
nothing to be missing from.IP allowlist
CIDR ranges, IPv4 and IPv6:CORS
Access-Control-Allow-Origin follows the origin check alone, not the overall verdict:
That split is deliberate: a listed origin refused for another reason — its address, its signature —
can still read the
403 from script, rather than seeing an opaque CORS failure with nothing in it.
Only the Origin header is echoed. An origin matched through Referer came from a no-cors request,
which reads no CORS header anyway.
Preflights
A preflight is answered on the allowlists alone, before any signature check and without reading the file — a preflight carries no credentials by definition, and the real request that follows is checked in full.What a refusal tells you
403, and nothing else. The response never says which check refused.
That is on purpose: telling a caller which check failed tells them which header to forge. Which check
refused is recorded in Livry’s own telemetry — if you are stuck, ask us.
Restricted Themes are not shared-cached
A Theme that restricts by origin or by address is served with cache directives that forbid a
shared cache from storing it. A CDN or corporate proxy holding a copy would answer the next
caller without running any of these checks.The cost is that a restricted Theme is slower than an unrestricted one. If you want CDN caching and
access control together, use signing — a signed URL is safe to cache,
because holding it is the credential.