Skip to content
Fermium

Sandboxing

Every document renders inside a Content-Security-Policy sandbox with an opaque origin. What that means for pages and for readers.

Published HTML runs in the reader's browser. Fermium cannot know whether a page is a harmless report or something worse, so every page is fenced the same way.

The header

Every HTML and SVG response from the content host carries:

Content-Security-Policy: sandbox allow-scripts allow-forms allow-popups allow-modals allow-downloads

The important word is what is missing: allow-same-origin. Without it the browser gives the document an opaque origin. Consequences for the page's scripts:

  • they cannot read cookies, localStorage or sessionStorage for the content host, so one document cannot see another's viewer cookie;
  • they cannot make credentialed requests to fermium.app, because the opaque origin is not the app origin and cookies are not sent;
  • they cannot read other documents' responses, even from the same hostname;
  • document.domain, plugins, and top-level navigation of a parent frame are not available.

What still works: scripts and inline styles in the page, forms, window.open, alert and confirm dialogs, downloads, and fetches of the document's own files by relative path (they are same-document, unauthenticated, and the sandbox permits them). Interactive dashboards, charts and small apps work as intended.

Other headers on every file

Header Value Why
X-Content-Type-Options nosniff the browser trusts the declared type; a .txt cannot be coerced into HTML
Referrer-Policy no-referrer the secret slug is never leaked to third-party sites the page links to
X-Robots-Tag noindex, nofollow search engines do not index document URLs even if one is posted publicly
Cache-Control private, no-cache with an ETag for unlisted; private, no-store for password and Restricted shared caches never hold documents; gated content is never stored
Content-Disposition attachment for types that should not render inline, such as zip avoids drive-by rendering

The neutral not-found page carries the same headers and the same sandbox policy.

Content types

The server decides how to serve a file from its extension, from a fixed allowlist. Unknown extensions cannot be published. HTML and SVG are the sandboxed types; images, video, audio, PDF and plain text are served with their own types and nosniff. PDFs are served at the document root so the browser's own viewer opens them without any plugin or sandbox interaction.

Pages we render

Markdown pages, snippet pages, image viewers, media players and download pages are generated by the server. They are self-contained: no CDN, no third-party scripts. The mermaid diagram library is the one script they may load, served from the content host itself, and only when a page contains a mermaid fence. Nothing is ever injected into a page you published as HTML.

What the sandbox does not do

It does not stop a page from linking out, opening popups, or asking the reader to type something into a form that posts elsewhere. A phishing page is still a phishing page. Report abuse to hello@fermium.app and it will be taken down; the two-origin split is what keeps such a page from harming the rest of the service in the meantime.

The app host

fermium.app itself sends X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, and a Content-Security-Policy that allows only same-origin scripts and styles on the server-rendered pages.