File Uploads 📎
All note tiers in SigNote support file attachments. Files are embedded directly into the note body using the rich text editor — images render inline, and other files appear as download cards.
Attaching files
To attach a file, open a note for editing and either:
- Drag and drop a file anywhere onto the editor
- Click the drop zone at the bottom of the editor to open a file picker
Multiple files can be uploaded at once. Each file is uploaded immediately when added and embedded into the note at the cursor position.
Supported file types
| Category | Formats |
|---|---|
| Images | JPEG, PNG, GIF, WebP, SVG |
| Documents | PDF, DOCX, XLSX |
| Text | TXT, CSV, Markdown |
| Archives | ZIP |
Images render inline with a preview. All other files appear as a card showing the filename, type, and size, with a download button.
Encrypted files (attached to Secrets or Seals) bypass the MIME type check — any file type can be uploaded when encryption is active.
Limits
| Limit | Value |
|---|---|
| Max file size | 5 MB |
| Total storage/user | 100 MB |
Encryption 🔐
File encryption follows the same model as note body encryption. The tier the file belongs to determines how it is handled:
Tier 1 — Notes
Files are uploaded and stored as-is. No encryption is applied, matching the plaintext nature of the Notes tier.
Tier 2 — Secrets
Before upload, the file bytes are encrypted client-side using AES-GCM 256-bit with the account's attachment key (fileEncKey), derived from the MEK. A fresh random 12-byte IV is generated per file. Only the ciphertext is sent to the server — the server never sees the original file.
When you download or view the file, it is decrypted in the browser using the active session key.
Tier 3 — Seals
A Seal's attachments are encrypted with the Seal's own note key — the same per-note key as its body — and bound to that Seal's id. Holding one Seal's key opens that Seal's files and nothing else's.
Because the key belongs to one Seal, so does the file:
- Pasting or dragging an attachment into a different note leaves it out, with a notice. Duplicating a Seal leaves its attachments behind for the same reason.
- The server will not link a Seal's file to any other note, whatever the request says.
- A new Seal gets its id and key when you open the editor, so files you attach before the first save are already under the key the Seal is saved with. A recovered draft keeps both.
Attachments added before Seal files were keyed this way are still under the account's attachment key. They open normally, and move onto their Seal's own key the next time you change your encryption keys. Moving a Secret to Seals re-encrypts its attachments under the new Seal's key as part of the move.
In all encrypted cases, if the MEK is not available (encryption is locked), uploading a file to a Secret or Seal is blocked until you unlock.
What is not encrypted
A file's contents are. Its name, type and size are stored in plaintext next to it, so the server knows that a note has, say, a 2 MB PDF called passport.pdf attached — just not what is in it.
Storage
Files are stored in AWS S3 or any S3-compatible provider (e.g. Cloudflare R2). The path structure is:
uploads/{userId}/{fileId}/filename # unencrypted
uploads/{userId}/{fileId}/encrypted # encrypted
See the self-hosting guide for the required S3 environment variables.
Attachments are never served offline
An attachment always requires a network connection, even in the installed app and even for a file you opened a minute ago. The service worker deliberately refuses to cache /api/files responses.
The reason is changing your encryption keys: a re-key re-encrypts every encrypted attachment and repoints the note at the new object. A cached copy from before that point is ciphertext under a key that no longer exists — it would fail to decrypt, or worse, appear to load and then produce nothing. A file that plainly says it needs a connection is the better failure.
Note bodies are unaffected; only file downloads are network-only.
What a key change does to attachments
When you change your encryption keys, each encrypted attachment is downloaded, decrypted, re-encrypted under the new key — a Seal's files under that Seal's newly generated note key — and uploaded as a new object — directly between your browser and the storage bucket over a short-lived signed URL, so the file never has to fit inside an ordinary API request. The note's pointer is switched to the new object in the same atomic step as everything else.
The old objects are not deleted immediately. They are queued and removed by a background job that runs once a day, because a transfer that began before the switch has to be allowed to finish first. Until that job has drained the queue, both copies count against your storage.
Soft delete
When a file is removed from a note (via the delete button on the attachment), it is soft-deleted: marked with a deletedAt timestamp in the database. The actual S3 object is permanently deleted after a 1-hour grace period by a background cleanup job.