Keeping the Forest Safe
Read this before you deploy anywhere but your own laptop. The woods are lovely, dark, and deep — and your email metadata should stay in them.
Three layers of dashboard access control
SquatchMail checks these in order (SquatchMail.Web.Router + SquatchMail.Web.Plugs.Auth). Exactly one applies to any dashboard request:
a) Host-owned authentication (recommended)
Mount the dashboard inside your own authenticated pipeline and pass your own on_mount hooks, exactly like Oban Web or Phoenix LiveDashboard:
scope "/" do
pipe_through [:browser, :require_admin_user]
squatch_mail_dashboard "/squatch", on_mount: [MyAppWeb.AdminAuth]
end
This is the only layer that can express real authorization — roles, per-user scoping, SSO. The layers below are a safety net, not a substitute.
b) Built-in fallback: HTTP Basic Auth
For small deployments that want something stronger than wide open without standing up an admin pipeline:
config :squatch_mail,
basic_auth: [
username: "squatch",
password: System.fetch_env!("SQUATCH_MAIL_PASSWORD")
]
c) Safe default: refuse
If neither (a) nor (b) applies, SquatchMail checks a runtime flag — deliberately not Mix.env(), which doesn’t exist in a release and would silently disable this exact safeguard in production — and renders a plain-language refusal page instead of dashboard data until access control is configured.
The gate stays shut until someone builds a fence.
The SNS webhook authenticates itself
The inbound webhook route is never covered by the dashboard layers above — it’s machine-to-machine and carries its own two locks:
- A URL token — the webhook path includes a per-source token.
- Hand-verified signatures —
SquatchMail.SNS.MessageVerifierverifies every inbound SNS message’s SigV1/SigV2 signature against:public_key, with no third-party dependency. It validates theSigningCertURLhost and scheme before ever fetching it, and caches parsed certificates in ETS for the certificate’s own validity window.
SquatchMail.SNS.Processor rejects any payload with a missing or invalid signature before it can touch your data. Every inbound payload — verified or not — is logged via SquatchMail.Tracker.log_webhook/1 for audit. Forged footprints get photographed, catalogued, and thrown out of court.
This is also why the raw-body reader matters: signatures are verified against the exact bytes SNS sent. Re-encoded JSON is not byte-identical, and tampered evidence is inadmissible.
Credentials at rest
credentials_mode: "ambient"(default) — AWS credentials come from the environment (IAM instance role, injected env vars). No keys touch your database. Use this.credentials_mode: "static"— keys stored as plaintext columns on thesourcestable today. Encryption at rest is a known gap, tracked as a TODO inSquatchMail.Source. Until it lands, prefer ambient.
Found a security issue?
See SECURITY.md for how to report it responsibly. Please don’t open a public issue for vulnerabilities — some things really should stay hidden in the woods until they’re fixed.