Security
Konten ini belum tersedia dalam bahasa Anda.
Email is attacker-controlled content that you have asked to be shown. The design assumes every message is hostile.
Rendering a message cannot run it
Section titled “Rendering a message cannot run it”Bodies are stored as sent — their CSS, tables, and layout intact, because mangling them is what makes self-hosted mail clients unpleasant. Safety comes from constraining what the page may do, not from rewriting it.
Each body is served under:
Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; img-src 'self' data:; ← widened only when you show images font-src data:; sandboxsandboxgives the document a unique origin and disables scripting. It applies even if the URL is opened directly in a tab, not only inside the frame.- The reading pane frames it with an empty
sandboxattribute, so the message never shares the dashboard’s origin. img-srcis what withholds remote images. Blocking is a header concern, which is precisely what allows the markup to be left alone.
Obvious active content is also stripped at ingest — <script> blocks, plain
on* handlers, and javascript:/vbscript: URLs — which costs no fidelity
because none of it affects how a message looks.
Treat that as tidying, not as a defence. It is regex over HTML, and HTML
has more ways to write an event handler than a regex can enumerate: a /
instead of a space before onerror, an entity-encoded scheme, a tab inside
javascript:, srcdoc, <meta http-equiv=refresh>. All of those get past it.
The CSP above is what actually stops scripts running, and it does not depend on the stripper being thorough. An earlier version of this page claimed the stripper would still hold if the CSP were misconfigured; that was wrong, and saying so mattered more than the sentence sounded.
Attachments
Section titled “Attachments”Always served with Content-Disposition: attachment and
X-Content-Type-Options: nosniff. Nothing opens in place.
Embedded images are inlined as data: URIs when the body is served, capped per
file and in total. SVG is excluded — it can carry script, and inlining it
would hand it the document’s origin.
Spam backpressure
Section titled “Spam backpressure”Unknown addresses that fail the catch-all guards are rejected with
setReject() at the SMTP level, so they never reach storage. The daily budget
for auto-created aliases means a spammer guessing addresses cannot mint
unlimited rows, and it counts only auto-created ones — aliases you made by hand
never consume it.
Over the limit, senders get a temporary failure and retry, so a real message caught in someone else’s burst is delayed rather than lost.
Secrets
Section titled “Secrets”- The session password is stored only as a salted PBKDF2 hash — the plaintext never leaves your machine. It and the cookie signing key are Worker secrets, so neither appears in the Worker’s plain-text settings.
- The two are separate values on purpose. Signing the cookie with the password hash, as an earlier release did, meant that reading the hash was enough to mint a session.
- The Cloudflare API token is not saved unless you opt in during setup;
when saved it goes to
~/.mailriz/config.jsonwith mode600. mailriz-cli statusreports whether a token is on disk, never its value.
What is not protected
Section titled “What is not protected”- Anyone with your Cloudflare account can read the mailbox directly through D1 and R2. MailRiz protects the dashboard, not your Cloudflare login — treat that account’s security as the real perimeter.
- Mail in transit is subject to whatever the sender negotiated. MailRiz receives what Cloudflare accepts.
- Access JWTs are signature-verified by the Worker against the team domain’s JWKS, plus audience, issuer, and expiry. See Authentication.