Purpose
What protects your customers' artwork, described accurately enough that you could check it.
A security page is usually a list of words a reader has no way to verify. This one is written from the mechanisms that exist, and each claim names something specific enough to be wrong. Where a protection is deliberately absent, it says so — the omissions are the honest part.
Your work is separated from everyone else's
Every proof, version, comment and approval belongs to exactly one workspace, and the separation is enforced by the database rather than by the application remembering to ask. Row-level security scopes every query to the workspace of the person making it; the workspace is resolved from the signed-in session, never from anything the browser sends.
Database functions that run with elevated privileges check membership themselves. Every one of them is called by an automated test as an outsider, and the test suite fails if a new function is added without such a case. That check has already caught a real defect: a storage-usage function that was readable across workspaces by any signed-in user, found and closed on 2026-07-29.
Review links
Your customer opens a proof without creating an account. That link is therefore the key, and it is treated as one.
- The token is long and random. Only its SHA-256 hash is stored for lookup, so the link cannot be reconstructed from a database copy.
- Links expire 60 days after your customer last opened one, and can be revoked or replaced by you at any time, which invalidates the old one immediately.
- Reviewer pages are never cached by shared caches, and the token never appears in a log, an error message or an error report.
- Repeated attempts against invalid tokens are rate-limited, and the response to an invalid link is deliberately identical to the response for one that never existed — guessing produces no information.
Artwork files
Uploaded files are stored privately. They are never publicly readable.
When your customer views a proof, the application mints a signed URL that is valid for three minutes and is issued only after the review token has been checked. The original file itself is immutable once uploaded: a revision is a new version, never a replacement, so what was approved cannot change afterwards.
Approvals
An approval names an exact version and that version's SHA-256 fingerprint. It cannot be edited or moved to a different version afterwards, and a project can carry only one live approval — enforced by a database constraint, not by convention.
The interface asks the reviewer to confirm they have reviewed a specific version and approve it for production. We do not describe this as a signature, and you should not either: it is a recorded, timestamped, attributed approval of a fingerprinted file, which is a strong and honest thing without borrowing a word that means something else in law.
The application itself
- Content Security Policy with a per-request nonce, so injected scripts have nothing to attach to.
- Origin and host validation on every state-changing request, with a body size ceiling, applied centrally rather than route by route.
- Rate limits on the paths that carry real abuse: sign-in, review-link access, commenting, upload sessions.
- Uploaded files are inspected in an isolated worker with a hard time and memory limit, so a malformed or hostile document cannot occupy the service.
- Dependencies are reviewed for known vulnerabilities.
What we deliberately do not collect
- No session recording. Our error-reporting tool supports it; it is switched off, because on this product a recording would be your customer's unreleased artwork, frame by frame.
- No request bodies in error reports, because a review token can travel in one.
- No analytics profile of your customers, and no cross-site tracking.
Error reports are scrubbed before they leave our servers: review links, signed URLs, bearer secrets and anything shaped like a key are replaced structurally — by walking the whole report, rather than by a list of fields somebody has to remember to extend.
Where your data is
Your artwork never leaves the EU. The database, authentication and file
storage are operated by Supabase in Ireland (eu-west-1), and the
application itself runs in Frankfurt. Those two hold everything that matters
here: your proofs, your customers' comments, and the files themselves.
A second copy of every uploaded original is held at a different provider, in a different account, in an EU-jurisdiction bucket — so losing one account does not lose the artwork, and a key stolen from either side reaches only one copy. Each copy is read back and checked against the fingerprint recorded at upload, because a file nobody has read is not a backup.
Four other services receive narrower things, and the Privacy Policy says exactly what: email delivery (Resend), payments (Dodo Payments), error reports (Sentry), and usage measurement of our own pages (PostHog, in Frankfurt — no cookie, no identifier stored in your browser, and nothing at all from a review link).
Operational practice
Production failures are visible rather than silent. The application reports which build it is running, checks its own database and storage continuously, and raises alerts on conditions a person would want to know about — a stalled preview queue, a broken reviewer route, an approval-integrity violation. The alert path is tested on purpose and repeatably, because an alert nobody receives is the same as no alert.
Rolling back a bad release has been rehearsed against production, both directions, and takes under a minute.
Reporting a problem
If you believe you have found a security issue, write to support@proofavo.com. Tell us what you did and what you saw; you do not need to prove impact. We will acknowledge within 72 hours.
One address rather than a separate security alias, deliberately: a product this size is better served by an address that is definitely read than by one that exists to look thorough.
We will not pursue you for a good-faith report made without accessing other people's data.