Product · Security

Secure document signing

Every layer of the signing process is secured: transport encryption, storage encryption, OTP identity verification, PKCS#7 digital sealing, hash-chained audit logs, and strict tenant data isolation. Not security theater — technical enforcement at every level.

Eight security layers on every envelope

🔐
Transport security

TLS 1.2+ for all API calls and the signing page. No plain-HTTP fallback. HSTS enforced.

🗄️
Storage encryption

Documents stored in Cloudflare R2 with AES-256 encryption at rest. Storage keys are per-document — no shared encryption keys across tenants.

📱
OTP identity verification

Every signer verifies identity with a time-limited one-time code sent to their email or phone before accessing the document. Prevents unauthorized access via forwarded links.

🏢
Tenant data isolation

All queries scope by app_id and tenant_id. Cross-tenant data access is architecturally impossible — not just policy-enforced.

🔏
PKCS#7 digital seal

A CA-issued PKCS#7 signature is applied to the entire document after signing completes. Any byte-level modification after sealing invalidates the signature — detectable in any PDF reader.

⛓️
Hash-chained audit log

Every signing event is appended to an append-only, hash-chained log. UPDATE and DELETE grants on the log table are revoked at the database level. Tampering with any row breaks the chain.

#️⃣
Document hash verification

SHA-256 hashes of both the original and sealed PDFs are stored. Any copy of the document can be verified against the stored hashes even after the file is deleted.

🔑
HMAC-signed webhooks

Webhook POST bodies are signed with HMAC-SHA256. Receivers verify the X-GetSigned-Signature header before processing to ensure the event originated from GetSigned.

Threat model

How GetSigned addresses each category of signing security risk.

ThreatMitigation
Unauthorized signer accessTokenized single-use signing links (short TTL, scoped to one envelope) + OTP verification before access is granted.
Document modification after signingPKCS#7 seal applied to the entire file. Any byte change — content, metadata, annotations — invalidates the signature.
Audit log tamperingHash-chain: each log row hashes the previous row. Any modification breaks the chain. DB-level REVOKE prevents UPDATE/DELETE on the audit_log table.
Cross-tenant data accessEvery query is scoped by app_id + tenant_id. There is no query path that bypasses this scope — no API endpoint returns unscoped data.
Forged webhook eventsHMAC-SHA256 signature on every webhook POST body. Receivers that verify the header cannot be fooled by replayed or forged events.
Credential theft via client appClient credentials are service-to-service only. Signers authenticate via tokenized links — they never hold credentials. Signer tokens are single-envelope, single-use, short-TTL.
Long-term certificate expiryTSA (Trusted Timestamp Authority) counter-signature embedded in the PKCS#7 seal proves the document was signed while the certificate was valid — regardless of future expiry.

Frequently asked questions

How does GetSigned prevent a signed document from being tampered with after signing?

After all signers complete, GetSigned flattens the signature fields into the PDF, appends an audit certificate page, and applies a CA-issued PKCS#7 digital signature to the entire file. The PKCS#7 signature covers every byte of the document — if any byte changes (content, metadata, a pixel, a character), the digital signature becomes invalid. This is verifiable by anyone with the document using Adobe Reader or any PDF validator. No special software or API access is needed to verify the document.

How does GetSigned prevent one signer from accessing another signer's link?

Each signer receives a unique, independently generated tokenized link (a short-TTL signed JWT scoped to exactly one envelope and one signer). The links are not guessable or derivable from each other. After the token is used to complete signing, it is invalidated. Additionally, OTP verification is required before the document is displayed — so even if a link were forwarded, the recipient would need access to the registered email or phone to complete the OTP step.

Is the audit log tamper-proof?

It is tamper-evident, not tamper-proof. "Tamper-proof" would require physical access controls beyond what a software system can provide. "Tamper-evident" means: (1) UPDATE and DELETE grants on the audit_log table are revoked at the database level, so the application role cannot modify rows; (2) each row hashes the previous row — a hash chain — so any modification of a historical row produces a detectable break in the chain; (3) the hashes are also embedded in the sealed PDF, making comparison against the stored chain possible even from an offline document.

What encryption is used for stored documents?

Documents are stored on Cloudflare R2 with AES-256 encryption at rest. Storage keys are generated per-document — there are no shared encryption keys across envelopes or tenants. Documents are only accessible through the GetSigned API with a valid bearer token scoped to the correct application and tenant. No public or anonymous access to document storage is possible.

How is cross-tenant data isolation enforced?

Every database query that touches envelopes, documents, signers, fields, or events is scoped by both app_id and tenant_id. This is enforced at the repository/data-access layer, not just at the API layer — there is no query path that can return results across tenant boundaries. This is considered the top-priority security invariant in the system architecture.

Related: Audit trail guide · Digital signature API · Compliance guide · E-sig vs digital sig

Security built in, not bolted on

Every envelope is secured at every layer automatically. No security configuration required.

Get free API keys →