Security
Your PDFs never leave your browser.
Not "encrypted in transit." Not "stored briefly." Not at all. The PDF bytes are parsed, edited, redacted, and signed inside the browser tab you have open. The server never sees them — and most of the time, the server isn't even contacted.
This page documents what runs where, what we encrypt, and exactly how you can verify our claims yourself.
What stays local, what touches our server
The honest, two-column truth. The left column is the work you do on your PDF; the right column is what (if anything) leaves your browser to do it.
| What you're doing | What leaves your browser |
|---|---|
| Filling a form (manually) | Nothing. PDF + your typed values stay in-page. |
| Signing yourself (one-click) | Nothing. Signature image is rendered + flattened into the PDF locally. |
| Redacting (manual selection) | Nothing. We draw black rects locally and re-save. |
| Merging, splitting, rotating pages | Nothing. pdf-lib in your browser. |
| OCR (making a scan searchable) | Nothing. Tesseract.js runs in your browser; the trained language data is a static asset served once from our CDN, not your scan. |
| Auto-fill from your saved profile | Form-field names + types (e.g. "first_name" / text) + your profile values. Not the PDF bytes. Sent to a third-party AI provider to compute the mapping. We don't log it. |
| AI redaction suggestions ("Scan for PII") | Extracted text spans (e.g. "123-45-6789"). Coordinates stay local. Sent to a third-party AI provider; not logged. PDF bytes never sent. |
| AI clause review | Extracted document text (no coords, no bytes). Sent to a third-party AI provider; not logged. |
| Counsel Mode (Pro / Max) | Nothing leaves your machine. AI runs against a local Ollama instance you control. The cloud AI provider is not invoked. |
| Send for signature | Ciphertext only — see below. Key never touches our server. |
| Signing in / paying | Email (Better Auth), payment metadata (Stripe). Standard. |
Bold rows are the only paths where any document-derived data leaves your machine — and even then, only text we've extracted client-side, never the PDF itself. You can confirm this by opening DevTools → Network and watching what gets sent.
How send-for-signature stays end-to-end encrypted
Send-to-sign is the only flow where your PDF visits our server at all — and only as opaque bytes we can't read. The flow:
- Your browser generates a random 256-bit AES-GCM key.
- The PDF is encrypted in-page with that key. Only ciphertext and the IV leave the tab.
- We store the ciphertext on our server (Google Cloud + Neon).
- The recipient link looks like
https://attachkit.com/sign/<id>#k=<base64-key>. The fragment after#is the key — and browsers never include URL fragments in HTTP requests (per RFC 3986 §3.5). Our server only ever sees the path. - When the recipient opens the link, their browser reads the fragment, downloads the ciphertext, and decrypts in-page. Our server is not asked for, and never holds, the key.
- After signing, the recipient's browser encrypts the signed PDF with the same key + uploads ciphertext. Same guarantee: we cannot read it.
The trade-off, stated plainly. Anyone holding the full link (including the fragment) can decrypt and sign. Treat the link like a password — share via a secure channel, don't paste in public chats, and let pending requests expire when they're no longer needed.
Cryptography in use
- AES-GCM-256 for at-rest PDF payloads on the send-to-sign path. Native WebCrypto (
crypto.subtle), no third-party crypto library to audit. - TLS 1.2+ in transit for every HTTPS request (HSTS preload enforced — see hstspreload.org).
- Session cookies via Better Auth — HTTP-only, Secure, SameSite=Lax. No tracking cookies, no third-party fingerprints.
- No account passwords.Sign-in is passkey / WebAuthn + email one-time-code only — there's no account password to steal. The optional signature-vault passphrase is stretched with PBKDF2-SHA256 and never leaves your device.
- WebAuthn ceremony policy. AttachKit's hardware-key signing ceremony uses
userVerification: "preferred", not"required". This means the authenticator is asked to perform user verification (biometric / PIN) when it can, but a roaming security key without a biometric won't hard-block the sign. The deliberate trade-off is broader hardware compatibility (older YubiKeys, generic FIDO2 tokens) at the cost of strict UV enforcement. If you're using AttachKit for a notarial or high-assurance flow that depends on biometric being captured at sign time, choose a passkey on a platform authenticator (Touch ID, Windows Hello, Android biometric) where UV is intrinsic. The signed clientDataJSON records the UV flag the authenticator actually set, so a verifier can audit this post-hoc. - Content Security headers: HSTS (2-year max-age + includeSubDomains + preload), X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy no-referrer (to harden the fragment-as-key trick against any proxy shenanigans), Permissions-Policy locking down camera / mic / geolocation.
Compliance posture (the honest version)
We're pre-launch and don't yet have third-party attestations. Here's what we do have, and what we don't:
- GDPR / UK GDPR. For your own account data — your login email, the profile you save with us, and analytics — AttachKit is the data controller. We act as a processoronly when a business customer uses AttachKit to handle their own end-users' data (covered by our DPA). See the DPA for the full contractual framing, sub-processor list, and international-transfer position.
- CCPA / CPRA. Same posture — the same delete + export endpoints in your account cover your CCPA rights.
- HIPAA.Not in scope — we don't hold PHI on the server (PDFs are local), but we don't sign BAAs and you shouldn't treat AttachKit as a HIPAA environment for the AI paths until we publish one.
- SOC 2 / ISO 27001.Not yet. We're a small team and the cost of an audit ahead of revenue doesn't pencil out. We'll start the SOC 2 Type I process when we have enterprise customers actually asking.
- 21 CFR Part 11 / FDA. Not in scope.
- ESIGN Act / eIDAS (simple e-signatures). Yes. PDFs signed via AttachKit are valid simple electronic signatures under both. They are not"qualified electronic signatures" (QES) under eIDAS — that requires a CA-issued certificate, which is a separate roadmap item.
Trust, but verify
Don't take our word for it. Every claim above is something you can check yourself in a few minutes:
1. Open the network tab while you work
DevTools → Network → load https://attachkit.com/app/sign → drop a PDF. Filter by "Fetch/XHR." You'll see the page loads and the PDF.js worker; you will not see your PDF being uploaded. Click Sign, type, save — still no PDF upload. This is the simplest one-minute proof.
2. Inspect the request bodies on AI paths
For Auto-fill, click the API call to /api/autofill → Payload tab. You'll see fields + profile as JSON — no PDF bytes. Same for /api/redact (text spans, no bytes) and /api/clause-review (document text, no bytes, no coordinates).
3. Pull the page offline and watch it still work
After loading /app/signonce, open DevTools → Network → throttle to "Offline" → drop a PDF → sign → download. It works. (The AI features will fail, since they need the network; everything else doesn't.)
4. Read the code
The PDF parsing + editing path is src/lib/pdf/*.ts + the in-browser pdf-lib / pdfjs-distimports. There's no "upload the PDF" codepath to grep for, because it doesn't exist. The AI endpoints in src/app/api/* take the shapes we describe above; no path accepts raw PDF bytes from a non-send-to-sign caller.
Reporting a vulnerability
Found something? Use our contact form and pick “Security vulnerability.” We acknowledge inside one business day and work the fix with you. No formal bug bounty yet, but we'll credit responsibly-disclosed findings if you want.
For pre-launch we don't have a separate security alias, PGP key, or HackerOne program — when those exist, this page is where we'll publish them.