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,
localStorageorsessionStoragefor 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.