This page lists what Morvero actually does, control by control, with a pointer to the part of the system that implements it. It is written for the person who has to sign off on putting a third-party script on an application portfolio — so it also states, plainly, what we do not have yet.
The most useful true statement about Morvero, for a privacy office, is that there is very little personal data here to protect in the first place.
| Control | Where it lives |
|---|---|
| Visitor IP addresses are never stored. The request IP is resolved to an ISO 3166-1 country code in-process, and only the country code is written. | Collection |
| Geolocation runs against a local database, so no third party sees a visitor IP either. | Collection |
The widget sets no cookies. A visitor is a random, meaningless id (v_…) generated in the browser and kept in that browser's own storage, alongside the widget's sampling and cooldown state. It contains no personal data, is never joined to a directory or identity provider, and cannot follow a person across devices. No fingerprinting, no identity resolution, no cross-site tracking. | Widget |
| We collect page paths, titles, ratings, comments and — only when a user chooses to attach one — a screenshot of the page. Submission is explicitly anonymous in the UI, and the widget asks users not to include personal details. A screenshot excludes the widget itself. | Collection |
| Because the widget stores nothing on the device beyond that random id, employee-facing deployments do not need a consent banner for the widget itself. (Our own marketing pages at morvero.com carry an affiliate referral tracker from our merchant of record. It runs only there — never in the widget, the console, or any self-hosted install. See the Privacy Policy, section 8.) | Widget |
| Cohort labels (e.g. department) are aggregate-only behind a k-anonymity floor of 5. A cohort with fewer than 5 distinct visitors is withheld entirely, the rating floor is applied separately so a cohort cannot clear the visitor floor on two ratings, and the console reports how many cohorts were suppressed rather than hiding the omission. | Analytics |
| Visitor free text is redacted before it is written: email addresses, phone numbers, Turkish national IDs (TCKN), IBANs and card numbers are stripped from feedback comments and captured form values, and the number removed is kept on the record as evidence. Because redaction happens at write time, every downstream consumer — exports, webhooks, AI summarisation, the console — only ever sees the redacted text. | Collection |
| Numbers that carry a checksum are validated, not pattern-matched, so a real national ID is removed while an order number of the same length survives and the feedback stays readable. | Collection |
Per-product switches are the right control for one team and the wrong one for fifty. These are the controls that outrank the product owner.
| Control | Where it lives |
|---|---|
| Screenshot attachment and form-entry capture can be locked off for the entire workspace by a privacy operator. While locked, product owners and AI agents acting through our MCP endpoint are both refused, with the reason stated. | Workspace policy |
| A lock is evaluated at collection time, so it takes effect immediately on products that were already collecting — a stale, cached widget's payload is dropped rather than stored. | Collection |
| Locking does not overwrite each product's own setting, so unlocking restores what each owner had chosen instead of silently switching collection back on across the estate. | Workspace policy |
| Tightening and loosening the policy are both written to the audit log. | Audit log |
| Per-workspace PII redaction can be turned off by a privacy operator if your own policy requires the raw text; it is on by default. | Workspace policy |
| Control | Where it lives |
|---|---|
| The install snippet is version-pinned and carries a Subresource Integrity hash. The versioned URL is immutable, and a request for a version we do not hold returns 404 rather than different bytes. | Widget delivery |
| Your pages therefore cannot silently begin executing different code — including if our own origin were compromised. The browser refuses anything whose hash does not match. | Widget delivery |
The current version, hash and path are machine-readable at GET /api/widget-asset, so you can automate your pin and your Content-Security-Policy. | Public API |
The widget renders inside a closed Shadow DOM and loads async: your CSS cannot break it, it cannot break your page, and it never blocks rendering. | Widget |
| Widget size is held to a gzipped budget enforced as a build failure, so it cannot quietly grow into a Core Web Vitals problem on your pages. | Build |
| Deactivating a product is an instant kill switch that needs no deploy on your side: the key stops being accepted and the widget goes dormant. | Console |
| An optional domain allowlist means a leaked key cannot be used from an origin you did not authorise. | Console |
| Control | Where it lives |
|---|---|
| Console accounts have no passwords at all — authentication is passkeys (WebAuthn) plus single-use 15-minute email links. There is no password to phish, reuse or leak. (Shared report links are separate and may optionally carry a password you set.) | Auth |
| Session tokens are stored as SHA-256 hashes, never in the clear; a stolen database yields no usable session. OAuth tokens and read API keys are hashed the same way. | Auth |
In transit, all traffic is served over TLS, with HSTS (max-age of one year, includeSubDomains) on every response in production. | Transport |
| At rest, data lives in a managed PostgreSQL instance (see subprocessors). Integration credentials your workspace stores with us — Jira and Azure DevOps tokens, webhook signing secrets — are additionally sealed application-side with AES-256-GCM before they touch the database, under a key held only in the runtime environment. | Storage |
Console sessions are HttpOnly, SameSite cookies, Secure in production. | Auth |
| AI coding agents connect over OAuth 2.1 with granular, user-revocable grants — every user can see and revoke their connected apps. Authorization codes are single-use with a 5-minute lifetime, and PKCE (S256) is mandatory: no public client ever authenticates with a secret. | Auth |
| SAML single sign-on with just-in-time provisioning and claimed-domain uniqueness. | Auth |
| SSO can be enforced, which closes the email-link and passkey doors as well — so deprovisioning someone in your identity provider actually revokes their access here. Enforcement cannot be switched on until a break-glass owner is designated, so an IdP outage cannot lock you out of your own data, and that exemption is flagged in the access review. | Auth |
| Optional TOTP two-factor, required on every interactive login once enabled — including passkey logins. | Auth |
| Roles are owner / admin / member / viewer, plus a privacy-operator capability and a per-product owner position. Every query is workspace-scoped. | Authorization |
| Access review export: every person, every product they can reach, and the specific grant that gives it to them — direct assignment, squad, product owner, or tribe lead — so a quarterly review can revoke the actual grant instead of guessing. Active platform-support windows are listed in the same report. | Console |
| Control | Where it lives |
|---|---|
| Multi-tenant with workspace-scoped authorization on every route; product data is only reachable through the owning workspace. | Authorization |
| A per-tenant audit log covering logins, role changes, grants and revocations, impersonation, exports and deletions — exportable by an owner as CSV for your SIEM. | Audit log |
| Morvero staff access to your workspace is break-glass: it requires your owner's consent, records a stated reason, is time-boxed, expires on its own, is visible to you, and is audited. | Support access |
| Control | Where it lives |
|---|---|
| A per-workspace retention window, enforced by a scheduled hard delete — not a soft flag. | Retention |
| Subject rights: look up and erase everything held for a given visitor id. | Privacy tools |
| Portability: a full workspace export as JSON, owner-initiated and audited. | Privacy tools |
| Deleting a workspace deletes its products, feedback, events, admins and grants. | Storage |
| Control | Where it lives |
|---|---|
Strict security headers on every response: Content-Security-Policy, X-Frame-Options / frame-ancestors, nosniff, Referrer-Policy, Cross-Origin-Opener-Policy, and HSTS in production. Framing is refused everywhere except two deliberate cases: our /docs page, which the console iframes same-origin, and public share pages, which are read-only aggregates meant to be embedded in Confluence or Notion. | HTTP layer |
| An SSRF egress guard on every outbound integration call (webhooks, Jira, Azure DevOps) refuses private-network destinations, so a hostile URL cannot be used to reach inside a network. | Egress |
| Rate limiting on authentication, collection and API surfaces; anti-enumeration behaviour on sign-in so email addresses cannot be probed. | HTTP layer |
| CSV exports are formula-injection safe — visitor-supplied text cannot execute when the export is opened in Excel or Sheets. | Exports |
JSON webhooks are HMAC-signed (X-Morvero-Signature) so your receiver can verify origin. Slack-format webhooks are unsigned by design, following Slack's own model in which the webhook URL is itself the secret. | Webhooks |
Vulnerability disclosure at /security and /.well-known/security.txt (RFC 9116). We acknowledge reports within 3 business days. | Disclosure |
Third parties that process workspace data on our behalf. A self-hosted install uses none of them except any you configure yourself.
| Provider | Purpose | Data involved |
|---|---|---|
| Railway | Application hosting & managed PostgreSQL | All workspace data |
| Postmark (ActiveCampaign) | Transactional email | Admin email addresses, email content |
| Anthropic | AI features (backlog copilot, theme summaries) — only when your plan has AI features enabled | Feedback text sent for summarisation, after redaction |
We want to hear about it. Email security@morvero.com with reproduction steps; machine-readable contact details are published at /.well-known/security.txt (RFC 9116). We commit to acknowledging reports within 3 business days.
While researching, please do not access other tenants' data — open a free workspace of your own and test against that. We will not pursue action against good-faith research that respects that boundary.
Stated plainly, because a vendor who claims everything is the one worth worrying about. Each line stays here until it is no longer true.
| Gap | Status |
|---|---|
| SOC 2 | Not attested. An internal control mapping and gap list exist; no report has been issued. |
| ISO 27001 | Not certified. Path and timing not yet chosen. |
| Independent penetration test | Not yet commissioned. No third-party report exists. |
| Public status page | A health endpoint exists and is monitor-ready; the hosted status page is not up. |
| Documented RPO/RTO and a tested restore | Backups exist; a restore has not yet been drilled and recorded. We will not quote an availability figure we cannot evidence. |
| SCIM provisioning | SAML JIT provisions users, but there is no automated deprovisioning yet. Removing someone from your IdP does not remove them here unless you have SSO enforcement switched on. |
| WCAG 2.1 AA conformance statement | Not independently audited. No VPAT yet. |
| Data processing agreement | No standard DPA is published yet; available on request in the meantime. Our subprocessors are listed above, but there is no formal change-notification mechanism for that list yet. |
If something you need is on that list, ask — several of these are scheduled, and knowing which one is blocking a decision changes what we do first.