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
Envelope encryption for session recordings and stored tokens, with a per-project key wrapped by a master key held outside the database. Disk-level encryption is listed as a gap below rather than claimed here.
Authentication
Argon2id password hashing, and sessions in httpOnly cookies scoped to one origin. Passkeys, TOTP and SSO are configured on the server and are not reachable yet, which is in the gaps below.
Authorisation
A permission matrix as data rather than scattered conditionals, checked at the route boundary and again at the repository boundary.
Input handling
Zod schema validation at every boundary, and parameterised queries everywhere. Every ClickHouse query is project-scoped by construction rather than by remembering a filter.
Secrets
Never in the repository. gitleaks scans the full history on every pipeline run.
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, in Sweden, and proven by an actual restore rather than assumed, because an untested backup is a hypothesis. Off-site copies are a gap below.
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.