Security and CORS
What the loader accepts in the browser and what the local server allows on your Mac.
In the browser
Stagepass does not allow arbitrary remote injection. Controls exist in both the loader and the CLI:
- Session domains: The loader only accepts
*.sp,localhost,localhost:<port>, ordebug. Invalid values are cleared fromlocalStorage. - Asset tagging: Tagged elements use
data-src/data-hrefas the production source of truth; originals are removed after the replacement is inserted (no double-load). - No session → production URLs: Without an active session, tagged assets keep production URLs (optional
?v=fromdata-stagepass-version/data-stagepass-v). - Quiet Stagepass logs:
sp.log/sp.warn/sp.errorare no-ops without a session; the global console is not muted unlessdata-stagepass-mute-console="true". - Caddy CORS + path blocking: Linked
.spsites reflect ACAO only for the allowlist below; blocked paths (.git,.env,node_modules, key/cert/db/log extensions) always 404.
- Sessions expire after 12 hours by default. Broken or expired values are cleared.
- Only tag files you build yourself. Stagepass swaps whatever you tag.
On your Mac
The CLI runs Caddy with a local certificate authority (tls internal), so https://<domain>.sp works with valid SSL on your Mac only.
Linked sites are hardened automatically:
Blocked paths (always)
These always return 404 (including OPTIONS), including with --allow-all-origins, and never reach PHP or file_server:
- Any path segment starting with
.(covers.git,.env,.env.local,.DS_Store,.ssh,.npmrc, …) node_modules/- Extensions:
.pem,.key,.p12,.pfx,.crt,.cer,.sqlite,.db,.log
CORS (cross-origin embedding)
Stagepass reflects Access-Control-Allow-Origin for allowed browser Origin values (no credentials):
Default allowlist (always on):
https://*.sphttp(s)://localhost[:port]andhttp(s)://127.0.0.1[:port]- Per-project live domains from
--origin/~/.stagepass/projects.json
Webflow staging/live hosts are not included by default. Add them per project, e.g. --origin my-project.webflow.io. An explicit --origin *.webflow.io (or *.webflow.com) is accepted but prints a warning (any Webflow user's site would then be allowed).
Matching responses also send Vary: Origin. Preflight (OPTIONS) for allowed origins returns 204 with reflected ACAO, Access-Control-Allow-Methods: GET, HEAD, POST, OPTIONS, reflected Access-Control-Allow-Headers, Access-Control-Max-Age: 86400, and Access-Control-Allow-Private-Network: true (Chrome Private Network Access from public HTTPS → loopback).
Non-matching origins get no ACAO. Non-allowlisted OPTIONS still get 204 without CORS headers.
Domain & path validation
- Domains are lowercased, must be DNS-safe labels, and always end with
.sp. Invalid folder names are slugified when the domain is omitted. - Project roots refuse
/, your home directory, and common system roots (/Users,/System,/Library, …). Paths are escaped for the Caddyfile.
Project config
Per-domain settings live in ~/.stagepass/projects.json:
{
"version": 1,
"projects": {
"my-project.sp": {
"root": "/Users/you/Sites/my-project",
"origins": ["www.example.com"],
"allowAllOrigins": false
}
}
}Report a security issue
Found a security problem? Open a GitHub issue and leave out exploit details.