Skip to content
Security overview

The parts that touch personal data were built to be audited.

Veil processes the most sensitive material an organisation holds, on behalf of a request it is legally obliged to answer. This page is what a security review usually has to extract over three calls.

Data residency

Everything stays in the European Union.

There is no region setting to get wrong, because there is only one region. Each component below is pinned, not merely defaulted.

Where each component runs
ComponentRegionNote
Database and authenticationFrankfurtRow-level isolation per organisation
Object storageFrankfurtPrivate buckets, no public objects
Processing workersFrankfurt and AmsterdamNo public ingress beyond a health check
Web functionsFrankfurtPinned at the deployment level
Model inferenceEuropean providerIdentifiers stripped before the request leaves
Encryption and purge

A purge destroys the key, not just the rows.

The densest personal data in the system is encrypted with a per-case key, and that key is itself wrapped by a key belonging to your organisation.

  • Envelope encryption

    Entity surface text and the normalised document model are encrypted with AES-256-GCM inside the worker. The plaintext never reaches the browser and never reaches a log.

  • Crypto-shredding

    When a case purges, the case key is destroyed. Any copy that survives anywhere, including in a backup, is unreadable from that moment.

  • Encryption in transit

    TLS on every hop, including the internal call from the web tier to the processing worker, which is additionally gated by a shared secret.

Retention

Cases expire on a clock you set.

Retention is a plan-capped setting, not a support ticket. A released case purges on schedule and leaves an accountability record with no personal data in it.

Default retention after release
30 days
Maximum retention
Up to 90 days by plan
Unreleased cases
Purged at 180 days, with warnings first
What the purge removes
Objects, extractions, entity mentions, the case key
What the purge leaves
A tombstone: reference, dates, counts, quality summary
Access control

Nothing is listable, and nothing is long-lived.

  • Signed URLs only

    Storage is never browsable. Each object is reached through a single-object signed URL valid for five minutes to upload and two minutes to download, issued by a server route that re-checks membership and role at the moment of issue.

  • Row-level isolation

    Every tenant table carries the organisation id and a row-level security policy. Cross-organisation reads are refused by the database, not by application code.

  • Roles and multi-factor

    Owner, admin, member and viewer, with multi-factor authentication available on every plan and SAML single sign-on on the enterprise plan.

  • Dual control

    On the enterprise plan, releasing a bundle and marking an entity as the data subject each require a second approver, enforced inside the database transition function rather than in the interface.

Logging and audit

Logs carry counts. Never content.

  • No personal data in logs

    Loggers accept ids, counts, enumerations and durations through an allowlist serializer. A continuous integration rule blocks raw string interpolation into a logger call, so the property is enforced rather than remembered.

  • Model calls logged as arithmetic

    An inference call is recorded as token counts and chunk identifiers. The prompt and the completion are not written anywhere.

  • Append-only audit trail

    State transitions, entity decisions, bundle downloads, unredacted-view toggles and settings changes are appended through a single writer and cannot be edited or deleted afterwards.

Product integrity

The verifier is credible because it shares no code.

  • A banned dependency edge

    The verification package is forbidden by a lint rule from importing anything in the detection package. If the two shared code, a bug in the redactor could pass its own check.

  • Hostile input parsing

    Archive, email and office document parsers are treated as an attack surface: zip-slip and zip-bomb guards, a recursion depth cap, per-job memory and time budgets, and fuzzing in continuous integration.

  • Egress allowlist

    The processing worker can only reach the destinations it needs. There is no general outbound network access from the component that handles document content.

  • Quality gated in CI

    A labelled corpus of synthetic cases runs on every change to a detector, a prompt or a model version. A change that finds fewer of the planted third parties, or that starts removing the data subject, does not merge.

Sub-processors

Who else touches the data.

The complete list. A data processing agreement and the current version of this list are available on request.

  • Supabase

    Database, authentication and object storage

    Frankfurt, EU

  • Fly.io

    Document processing workers

    Frankfurt and Amsterdam, EU

  • Vercel

    Web application hosting

    Frankfurt, EU

  • Mistral AI

    Entity detection and optical character recognition

    EU

  • Stripe

    Billing. Never receives document content

    EU

Request the data processing agreement

Your next access request does not have to eat a week.

Open a case, declare the subject, drop the documents in. Veil does the rest and shows you its working.