Security
Written for whoever has to fill in the vendor questionnaire, including the questions with uncomfortable answers.
In the order these actually matter for an analytics platform.
One customer reading another customer's data
Catastrophic, and the whole product promise. Every analytical query is refused unless it carries a project predicate, the database ordering key starts with the project so a tenant's rows are physically separate, and an automated test attempts a cross-tenant read on every build.
A leak of personal data through analytics itself
IP addresses are never written to disk. Query strings pass an allowlist, so a token or an email in a URL is never received. Identifier-shaped path segments are masked before storage.
Compromise of the browser SDK
It runs on every customer page, so a compromise there is a compromise of every customer site. Zero dependencies, no install scripts, published integrity hashes for pinned releases, and self-hosting encouraged.
A stolen API key
Keys are scoped rather than general purpose. Ingest keys are public by design and can only write events to one project. Secret keys are shown once, hashed with argon2id at rest, and revocable within a minute.
Insider access to customer analytics
No standing access for anyone. Subject access requests and project setting changes are written to an append-only audit log you can read in the product, with the actor and the time. A customer-granted, expiring support access flow and break-glass with a second approver are specified and not built, so today there is no supported way for us to reach your analytics at all.
Server-side request forgery through customer-supplied URLs
Webhook destinations are resolved and checked against private, loopback, link-local and metadata ranges before any request is made, and redirects are re-validated.
Transport
TLS 1.3 externally, HSTS with preload, and a strict content security policy with no inline scripts.
At rest
Full-disk encryption on every data host, with envelope encryption for tokens and future session recordings.
Authentication
Argon2id password hashing, passkeys, TOTP, and enterprise SSO with SCIM. Re-authentication for destructive actions.
Authorisation
A permission matrix as data rather than scattered conditionals, checked at the route boundary and again at the repository boundary.
Input handling
Schema validation at every boundary, parameterised queries everywhere, and a lint rule that forbids string interpolation into SQL.
Secrets
Never in the repository. Automated secret scanning runs on every commit and in the pipeline.
Dependencies
Weekly automated updates, audited in the pipeline, with new transitive dependencies in the SDK requiring review.
Logging
Structured, with IP addresses, user agents, URLs with query strings and property values all prohibited. A test asserts none of them appear.
Backups
Encrypted, off-site in a second EU country, and restored in a scheduled drill because an untested backup is a hypothesis.
Isolation
Row-level security on tenant tables and per-tenant query limits so one project cannot degrade another.
If one of these is a hard requirement for you, better to find out here than three weeks into a procurement process.
Send it to security@metricward.eu. You will get a human response within 72 hours, and we will tell you what we are doing about it rather than going quiet. There is no paid bounty yet, and we would rather say so than imply one exists.
Please do not run automated scanners against production, do not access data belonging to anyone else, and give us a reasonable window before publishing. Beyond that, we are not going to threaten anybody who reports a real problem in good faith.
Machine readable at /.well-known/security.txt.