Security
Last updated: March 15, 2026
We believe privacy tools should be transparent about how they protect your data, not just that they do. This page explains exactly what happens when you use Privacy First Labs — in enough detail for a security engineer to evaluate, but readable by anyone.
The Core Principle
Your data never leaves your device. Every tool in Privacy First Labs processes data entirely in your browser using standard Web APIs. No files are uploaded. No plaintext is transmitted. No server-side processing occurs.
This isn't a policy — it's an architectural guarantee. Our tools are static pages served by Cloudflare Pages. There is no application server, no database, and no API endpoint that accepts your data. You can verify this yourself by opening your browser's network tab while using any tool.
SafeSeal Encryption
SafeSeal lets you encrypt secrets (passwords, API keys, credentials) with a password and share them as a link or file. Here is exactly how it works.
Encryption Algorithm
We use AES-256-GCM (Advanced Encryption Standard with 256-bit keys in Galois/Counter Mode) via the browser's built-in Web Crypto API. This is the same encryption standard used by governments, banks, and security-critical applications worldwide.
- AES-256 provides confidentiality — your secret is unreadable without the key
- GCM mode provides authentication — any tampering with the encrypted data is detected and rejected
- The Web Crypto API is a browser-native implementation, not a third-party JavaScript library that could be compromised
Key Derivation
Your password is never used directly as an encryption key. Instead, we derive a cryptographic key from it using PBKDF2 (Password-Based Key Derivation Function 2):
- Hash function: SHA-256
- Iterations: 600,000 — the minimum recommended by OWASP (2023) for SHA-256
- Salt: 16 bytes of cryptographically random data, unique per encryption
- Output: A 256-bit AES key
The high iteration count means that even if an attacker obtains the encrypted data, brute-forcing the password is computationally expensive. The random salt ensures that identical passwords produce different keys.
Encryption Process
When you click "Encrypt," the following happens entirely in your browser:
- A 16-byte random salt is generated using
crypto.getRandomValues() - A 12-byte random initialization vector (IV) is generated using
crypto.getRandomValues() - Your password + the salt are fed into PBKDF2 (600,000 iterations) to produce a 256-bit AES key
- Your secret is encrypted with AES-256-GCM using the derived key and the IV
- The output includes a 16-byte authentication tag (GCM's integrity check)
Both the salt and IV are randomly generated for every encryption. This means encrypting the same secret with the same password twice produces completely different ciphertext.
Link Mode
In link mode, the encrypted data is encoded into the URL fragment (the part after #):
privacyfirstlabs.io/safeseal/#1.<salt>.<iv>.<ciphertext>
The URL fragment is never sent to any server. This is not a choice we made — it is how the HTTP protocol works. Per RFC 3986 (Section 3.5), the fragment identifier is processed entirely by the client. When you open the link, your browser requests /safeseal/ from our server — the #... portion stays in your browser.
Components are encoded using base64url (RFC 4648, Section 5) for safe inclusion in URLs.
File Mode
In file mode, the encrypted data is packaged into a compact binary .pflenc file:
- Byte 0: format version (currently 1)
- Bytes 1–16: salt
- Bytes 17–28: IV
- Bytes 29+: ciphertext (including GCM authentication tag)
Before encryption, the original filename is embedded inside the payload using a compact header: a 2-byte length prefix followed by the UTF-8 filename, followed by the file data. This means the original filename is always recovered on decrypt — the recipient gets the file with its original name and extension.
The file is generated entirely in your browser and downloaded to your device. It is never uploaded to or stored on our servers. You share the file through whatever channel you prefer.
Filename Privacy
By default, encrypted files download as originalname.pflenc — making it easy to identify the file. If you prefer not to reveal the filename, the "Hide filename" option downloads the file as secret.pflenc instead.
The original filename is always encrypted inside the .pflenc payload regardless of this setting. On decrypt, the recipient always recovers the original filename from the encrypted data. The "Hide filename" checkbox only controls what the outer .pflenc file is named during download — it does not affect the encrypted contents.
Decryption Process
When the recipient opens the link or uploads the .pflenc file:
- The salt, IV, and ciphertext are extracted from the URL fragment or file
- The recipient enters the password
- PBKDF2 derives the same AES key from the password + salt (600,000 iterations)
- AES-256-GCM decrypts the ciphertext and verifies the authentication tag
- If the password is wrong or the data was tampered with, decryption fails with a generic error
The error message intentionally does not reveal which check failed (wrong password vs. corrupted data). This prevents attackers from using error differences to gain information about the encryption.
What Our Server Sees
For SafeSeal — nothing. Our server delivers static HTML, CSS, and JavaScript files. It does not receive, process, or store:
- Your secret text
- Your encryption password
- The encrypted data
- The decryption key
- Any URL fragments (technically impossible — browsers do not send fragments to servers)
Even if our servers were compromised, an attacker would obtain only the static site files — never your encrypted data or keys.
What We Cannot Do
Because of our zero-knowledge architecture:
- We cannot decrypt your secrets — we never have the keys
- We cannot recover your password — it exists only on your device and the recipient's device
- We cannot comply with requests to produce plaintext — we do not have it
- We cannot tell if a link has been used or how many times — we have no tracking
This is by design. The burden of key management is on you and your recipient. If the password is lost, the secret is unrecoverable.
Verify It Yourself
You don't have to take our word for it. Here's how to verify our claims:
- Network tab: Open your browser's Developer Tools (F12), go to the Network tab, and use SafeSeal. You will see zero network requests containing your secret or encrypted data
- Source code: Our encryption module is designed for open-source release. The core logic uses only the browser's native Web Crypto API — no third-party cryptographic libraries
- Offline test: Disconnect from the internet, then encrypt and decrypt a secret. It works — because nothing ever leaves your browser
Processing Isolation
All computationally intensive operations (key derivation, encryption, decryption) run in Web Workers — isolated background threads that:
- Keep the UI responsive while the 600,000 PBKDF2 iterations run
- Have no access to the DOM or the page's main JavaScript context
- Are created per-operation and terminated immediately after completing
- Do not persist any data between operations
Security Considerations
Password Strength
The security of your encrypted secret depends on your password. We enforce a minimum of 8 characters, but we strongly recommend using a longer passphrase. PBKDF2 with 600,000 iterations provides significant protection against brute-force attacks, but a weak password (like "password123") can still be guessed.
Link Sharing
When using link mode, the encrypted data is in the URL. Anyone with access to the full URL has the encrypted data (though they still need the password to decrypt it). Share links through secure channels, and always share the password through a different channel than the link.
Browser Security
Client-side encryption depends on a secure browser environment. If your browser or device is compromised (malware, malicious extensions), the encryption guarantees may not hold. Keep your browser and operating system up to date.
No Forward Secrecy
If an attacker captures the encrypted link or file and later obtains the password, they can decrypt the secret. For highly sensitive use cases, consider rotating passwords and using short-lived sharing methods.
Technical Summary
| Encryption | AES-256-GCM (Web Crypto API) |
|---|---|
| Key derivation | PBKDF2-SHA-256, 600,000 iterations |
| Salt | 16 bytes, cryptographically random, unique per encryption |
| IV | 12 bytes, cryptographically random, unique per encryption |
| Authentication | GCM mode (128-bit auth tag, included in ciphertext) |
| Key transport | URL fragment (never sent to server) or .pflenc file (downloaded locally) |
| Server involvement | None — static site only |
| Cryptographic library | Browser-native Web Crypto API (no third-party dependencies) |
| Target browsers | Last 2 versions of Chrome, Firefox, Safari, Edge (ES2022) |
Questions?
If you have questions about our encryption implementation, found a potential vulnerability, or want to discuss our security architecture:
Privacy First Labs
security@privacyfirstlabs.io
We welcome responsible disclosure and are committed to addressing security concerns promptly.