Skip to content

Allow multiple trusted origins for form submissions - #142

Merged
kittendevv merged 1 commit into
kittendevv:mainfrom
mauricewipf:mauricewipf/csrf-trusted-origins
Sep 7, 2026
Merged

Allow multiple trusted origins for form submissions#142
kittendevv merged 1 commit into
kittendevv:mainfrom
mauricewipf:mauricewipf/csrf-trusted-origins

Conversation

@mauricewipf

Copy link
Copy Markdown
Contributor

Summary

Adds an optional TRUSTED_ORIGINS env var so self-hosted deployments can accept form POSTs from more than one hostname (e.g. Umbrel .local plus Tailscale MagicDNS or LAN IP), while keeping CSRF protection enabled.

Existing installs with only ORIGIN set are unaffected — TRUSTED_ORIGINS is purely additive.

Fixes #133

Problem

When Invio is accessed over a hostname different from the configured ORIGIN, login and other form actions fail with:

{\"message\":\"Cross-site POST form submissions are forbidden\"}

Common example (Umbrel):

  • Local: http://umbrel.local:8003 — works
  • Tailscale: http://umbrel-home.<tailnet>.ts.net:8003 — rejected

SvelteKit's built-in CSRF only compares Origin against one server-side origin, and csrf.trustedOrigins in svelte.config.js is build-time — not configurable per install.

Solution

Move the CSRF origin gate into hooks.server.ts so the allowlist can be set at runtime:

  • ORIGIN — canonical origin (unchanged; still respected)
  • TRUSTED_ORIGINS — optional comma-separated extra origins
    • exact origins: http://tailscale.local:8000
    • glob: http://*.ts.net:8003
    • * to allow all (trusted networks only)
  • Skipped in dev (matches SvelteKit's built-in behavior)
  • When neither env var is set, allow same-host form posts only (Origin host matches request Host, scheme ignored). This fixes HTTP deployments where adapter-node would otherwise default to https:// origin.

Backward compatibility

Existing setup Change needed?
ORIGIN=http://localhost:8000 only (Docker) No
ORIGIN=http://\${DEVICE_DOMAIN_NAME}:8003 only (Umbrel) No
vite dev without env vars No (skipped in dev)
Tailscale / LAN IP access Opt in via TRUSTED_ORIGINS

Testing

  • Bun unit tests in frontend/src/lib/csrf.test.ts covering exact, glob, wildcard, missing origin, and Host-header fallback (bun run test)
  • Type check: bun run check — 0 errors (4 pre-existing warnings unrelated to this PR)
  • Verified locally with a production-mode sandbox (adapter-node + Deno backend) POSTing /login?/login from multiple hostnames via curl --resolve, all scenarios pass (canonical, extra trusted origin, glob, wildcard, empty-env same-host, blocked cross-host)

For Umbrel packaging (separate PR)

After this ships, the umbrel-apps invio/docker-compose.yml frontend service can add:

TRUSTED_ORIGINS: \"http://\${DEVICE_DOMAIN_NAME}:8003,http://\${DEVICE_HOSTNAME}:8003,http://*.ts.net:8003\"

Files

  • frontend/svelte.config.js — disable built-in origin gate (delegated to hook)
  • frontend/src/hooks.server.ts — production-only runtime CSRF check
  • frontend/src/lib/csrf.ts — matcher (exact/glob/wildcard + host-header fallback)
  • frontend/src/lib/csrf.test.ts — 13 unit tests
  • frontend/package.json — add test script and @types/bun devDependency
  • .env.example — document TRUSTED_ORIGINS

Made with Cursor

Adds an optional TRUSTED_ORIGINS env var so self-hosted deployments can
accept form POSTs from more than one hostname (e.g. Umbrel .local plus
Tailscale MagicDNS or LAN IP). Existing installs with only ORIGIN set
are unaffected.

- Move CSRF origin gating from SvelteKit's build-time check into
  hooks.server.ts so the allowlist is configurable at runtime
- Support exact origins, glob patterns (e.g. http://*.ts.net:8003),
  and "*" for trusted networks
- When neither env var is set, allow same-host form posts (Origin host
  matches request Host, scheme ignored) to fix HTTP deployments where
  adapter-node would otherwise default to https:// origin
- Skip the check in dev to match SvelteKit's built-in behavior
- Add Bun unit tests for the matcher

Fixes kittendevv#133

Co-authored-by: Cursor <cursoragent@cursor.com>
@kittendevv

Copy link
Copy Markdown
Owner

Thanks for this awesome work

@kittendevv
kittendevv merged commit 0c3c455 into kittendevv:main Sep 7, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Support multiple trusted origins for form submissions (Umbrel / Tailscale / LAN access)

2 participants