SIDR

Security

Facts, not badges.

What follows is how the product is actually built, what we record, what we never record, and where compliance genuinely stands today. There is no certification logo on this page, because we have not earned one yet. When we do, it will sit in the compliance section below and not in the headline.

How it is built.

Encryption at rest
Per-document envelope encryption with a per-tenant key. Each file is encrypted with AES-256-GCM using a data key generated under that tenant’s own key alias; the plaintext data key exists in memory only and is discarded immediately, and the wrapped key is stored beside the ciphertext. Deleting a document deletes its wrapped key and revokes the grant that could unwrap it, which leaves the stored ciphertext permanently undecryptable rather than merely marked as gone.
Tenant isolation
Postgres row-level security, enforced through a database role created as NOSUPERUSER NOBYPASSRLS. Every request sets that role for the transaction, so a policy cannot be silently bypassed by connecting as a superuser or as the table owner. There is a standing test that asserts the superuser bypass exists, so nobody can “fix” it by reconnecting as the owner.
Authorization
Every sensitive route goes through one central authorize(actor, action, resource) call and denies by default. A route never resolves its own tenant — the owning organisation comes from a single database function, so a route cannot accidentally compare an actor’s organisation with itself. A request for another organisation’s deal or document returns nothing distinguishable from “it does not exist”, which avoids confirming that it does. Row-level security is the second, independent layer beneath this, not the first one.
The reading room
Documents are rendered to raster tiles on the server. In view-only mode no route returns the original file’s bytes or anything derived from them: a full recipient session is driven end to end in a real browser in the test suite and every response body is checked for a %PDF- header — none has appeared. Tiles are served over short-lived signed URLs with Cache-Control: no-store, and watermarked output is never cached.
Staged disclosure
Every page and every region within a page carries a minimum disclosure level, checked on the server on each render request, and unmapped content fails closed at the highest level. Requesting a level-2 page as a level-1 reader by editing the address returns a hard refusal, not a page with something hidden on it. A redaction is a block composited into the raster before it is sent — never a mask over pixels the browser already has.
Revocation
Entitlement is re-checked on the server for every tile request, independently of how long any signed URL has left to live. Cutting a reader off is measured at 115 ms from revoke to refusal in our test environment against a 5-second production budget, and is tested against it.
Identity
Passkeys. Verification happens on the reader’s own device and we receive a cryptographic assertion, never a biometric image or template. Opening any disclosure level requires a fresh, server-generated, single-use challenge verified with user-verification required — which is a stronger check than signing in, and we do not describe signing in as proof that a person was present. There is no camera in this product.
The evidence chain
Every disclosure-relevant event is appended to a hash-chained log — never edited, never deleted — and batched into a Merkle tree whose root is anchored externally. Altering a past entry breaks the chain and the verifier detects it and names the entry. This is tamper-evident, which means detection; it is not prevention, and there is no write-once store yet.
Time anchors
Three, independent of each other and of us: RFC 3161 tokens from DigiCert and FreeTSA, and an OpenTimestamps commitment. Timestamped by three clocks you don’t own. The OpenTimestamps proof is a calendar commitment until it is included in a block, and we have not yet observed one of ours upgraded — the verifier and the certificate both print calendar rather than bitcoin until that happens.

What we log, and what we never log.

The evidence chain and the application logs are two different things with two different rules. The chain records decisions and acts — an agreement accepted, a level granted, a page served — because those are the product. The application logs record operations, and they are redacted at the serializer, which is a code-level control rather than a policy reminder.

The list on the right is not a summary of a longer internal list. It is the rule, and fields whose names match *token*, *secret*, *key*, *password* are stripped before a line is ever written.

Never logged, in any service, at any level

  • Document content — page text, agreement body text, file names beyond the generated storage key
  • Watermark payloads
  • Tokens, secrets, plaintext data keys, full session cookies
  • Raw biometric or identity-check payloads — these never reach us at all
  • Payment details — we do not collect them; the payment processor holds them and we store a reference

The evidence chain itself holds hashes and metadata. Document content is never in the evidence log — only what was served, to whom, when, and its hash.

The verifier does not talk to us.

An evidence package is a file you keep. The verifier that checks it is a standalone program with no connection to our servers and no dependency on our code being honest: it recomputes the hash chain from genesis, replays the Merkle inclusion proof, checks the RFC 3161 signatures, and rejects a token that claims to predate the event it covers.

It checks every byte of a timestamp token’s signature, not only the time it claims — measured against both anchoring authorities, byte for byte. At the last full measurement (HOLD 10, 2026-09-07), 497 tests ran green across four tiers, and the ones that mattered were the negative tests: every guard added that week was proven to fail closed first, by removing the fix and watching it catch the defect.

One limit stated plainly: nothing inside a package chains a timestamp authority’s certificate to a trusted root. The verifier says so on its own output rather than leaving you to discover it.

sidr-verify turtle-cove-evidence.zipchain1,204 events verified from genesismerkleinclusion proof OKrfc3161DigiCert OK · FreeTSA OKotscalendar commitment · no Bitcoin attestation observedbackdaterejected: token predates the event it covers

Open tools, your machine, no account. If we disappeared tomorrow, a package issued today would still verify.

Subprocessors.

Every vendor that can touch confidential or restricted data, what it touches, and why it is there. A vendor that would touch restricted data without a clear architectural reason is a rejected default, not a fast-tracked one.

Compute
Fly.io — documents pass through worker memory during rendering; nothing decrypted is written to its storage beyond ephemeral scratch.
Database
Neon — ciphertext and personal data, under row-level security.
CDN and tile storage
Cloudflare — rendered raster tiles only. The source document is never there.
Key management, archival storage
AWS — key management and the write-once store when it ships.
Evidence log hosting
Hetzner — audit metadata and hashes. Document content is never in the evidence log.
Time-stamping
DigiCert and FreeTSA — each receives a Merkle root hash and nothing else. No document content, no personal data.
Transactional email
Resend — recipient addresses and single-use, short-lived invitation tokens.
Identity verification
An identity-verification provider, named in the data-processing agreement, for the optional check at higher levels. Raw identity documents are handled entirely at that provider; we store a pass or fail result, the date, and a verification reference.
Authentication
None. Passkey verification happens on the reader’s device; no third party receives authentication data.

Data residency

Documents, keys and the evidence log are held in one region per tenant, and deletion is a per-tenant, per-region operation rather than a platform-wide one. Enterprise customers choose the region as part of the agreement. Ask us for the current default before you assume one — we would rather answer than have you guess from a map on a marketing page.

Responsible disclosure

If you find a vulnerability, write to security@sidr.so. We will acknowledge within 72 hours and tell you what we are doing about it. We will not threaten you, and we will credit you if you want the credit.

Compliance

SOC 2 Type 1 is scheduled with our first enterprise pilot, and is not in place today. That is the whole status. We are not going to put a badge in the header for a certification we have not been through, and we are not going to describe the controls above as “audited” when what they are is built and tested. When the report exists, it will be named in this section with its date and its scope, and available under NDA.

GDPR and Thai PDPA obligations are addressed architecturally rather than by policy alone: per-tenant keys mean a deletion request can be satisfied by destroying a key rather than by locating every replica of a file. A data-processing agreement is available for any customer who needs one.

The honest half

This page describes what the product does. The list of what it does not do is a separate page of equal length, and it is the one we would read first if we were you.

What SIDR does not do

Bring your security reviewer.

We will answer a questionnaire, walk your team through the architecture, and hand over an evidence package they can verify themselves without an account. Or set up a room and read the code paths from the outside.