Skip to content
Oxide
Esc
navigateopen⌘Jpreview
On this page

Security

What oxidejs guards by default in asset serving, server actions, and the dev server — and what stays your job.

oxidejs inherits all of tacho’s protocol guards and adds its own for the build output and dev server. Authentication, CORS, and rate limiting are still yours.

Asset serving (preset: "fetch")

The generated server serves static files from dist/client/ (or the public/ directory merged into it). These guards are active:

Attack vector Guard
Traversal (%2e%2e/, ..%2f) __rel() rejects paths containing .. segments.
Double-slash (///etc/passwd) __rel() rejects results that still start with / after slice(1).
Null byte (%00, \0) __rel() rejects paths containing null bytes before and after decodeURIComponent.
Absolute path (/etc/passwd) __rel() returns null for paths not starting with /.
SPA fallback Unknown paths → index.html, never a directory listing.
clientDir escape resolveOptions throws at build time if clientDir resolves outside outDir.
Hashed assets Files matching [-.][0-9a-f]{8,}.ext get Cache-Control: public, max-age=31536000, immutable. Other files are not cached by default.

The generated __asset function uses path.join — not path.resolve — so a leading / in the relative path stays inside the asset root.

Server actions (*.server.{ts,tsx,js,jsx})

  • Server action code is never bundled into the client. Client imports are replaced with tacho stubs that POST the action endpoint (default /__oxide/action). The original source stays server-only.
  • Only action()-wrapped exports are exposed as RPC; other exports stay server-local.
  • The endpoint is POST-only. Non-POST requests return 405.
  • Method dispatch uses Object.hasOwn, blocking __proto__ / constructor walks.
  • Unknown or missing content-types → 415.
  • Body size capped at 1 MB by default (enforced on the actual body, not just Content-Length).
  • Batch requests capped at 20 items (both HTTP and WebSocket transports).

Set sameOrigin: false only when you intentionally accept cross-origin calls and provide your own CORS, CSRF, and authentication rules. See middleware.

Host header

The generated dev server constructs request.url from req.headers.host. This is standard HTTP/1.1 behavior (same as Express, Hono, Koa, Node http). If your src/server.ts reads request.url to construct redirects, validate the host yourself — the framework cannot distinguish a legitimate host header from a malicious one. In production, your reverse proxy handles this.

Was this page helpful?