Small surface, published review
Missivus holds a credential that can send email as your company. That is exactly the kind of code that should be reviewed line by line and documented in public — so it was.
The security model in one paragraph
The Exchange application access policy is what bounds the blast radius. Every finding below is contained by it — even a fully compromised credential can send as one shared mailbox and do nothing else. That is why the installation guide treats the policy as a required step with a verification command, not as optional hardening.
What the review covered
The v0.1.1 tree was audited after the first live deployment — the Graph transport, the settings model, the test-email API method and the Vue component, checked for secret leakage through logs, API responses, HTML source and the browser console; authentication and CSRF on the API surface; input validation on every setting; and whether Graph error bodies can reach anyone but a superuser. Claims about Matomo behaviour were verified against Matomo's source, not recalled.
Findings, honestly stated
Fixed before release
- A base-URL override could have aimed the client secret at an attacker's host — URLs are now validated to be bare https origins before any request is built.
- A network failure mid-upload could leak a pre-authenticated upload URL into the log — now converted and redacted like every other failure.
- Settings accepted any string — every field now validates its shape, so a pasted Secret ID fails at save time, not as an opaque Microsoft error later.
- The test-email API method accepted any recipient and answered GET — now POST-only with a validated address, kept out of server access logs.
Verified clean
- Secrets never reach the HTML source, the API response, or the browser console — password fields are masked by Matomo core, and the plugin adds two guards of its own on top.
- The test call is CSRF-protected by Matomo's token model, with a POST-only rule added as defence in depth.
- Everything logged or thrown passes through a redactor that blanks known secrets by value and credentials by shape — tokens, assertions, bearer headers, upload URLs — and fails closed.
Accepted trade-offs, documented
- The short-lived access token is cached in Matomo's file-backed cache — anyone who can read it can already read Matomo's config, which may hold the secret itself. Mitigated by the 55-minute lifetime and the access policy.
- A superuser can send unthrottled test emails — a nuisance vector, not a privilege one; a superuser could reconfigure mail outright anyway.
- A secret entered in the settings UI is stored unencrypted in Matomo's database — the config-file and environment-variable tiers exist precisely so it never has to be, and they take precedence.
Reporting a vulnerability
Email the address below with the details. Please give us the chance to fix a problem before it becomes public — and never include a client secret, certificate or PEM file in a report.
Security contact:…