Disclosure first: Jobdossiers is a product of Swiss Security Insights, and I build both. SSI has no sponsors and this is not a review. It is a worked example of a threat model, written by the person who made the design choices and has to defend them.
It started with a spreadsheet. I am looking for a new role, and I began where most people in IT begin: an Excel file. I added AI to automate the repetitive parts, then moved the file to the cloud to reach it from anywhere. It worked badly on a phone and a tablet, so I looked at the existing online platforms. None reassured me on security. That is not an accusation of carelessness. I simply could not tell what the vendor could read, where my text went when AI features ran, or what would happen after a breach. A prototype for my own use became the idea for a product.
What the data is worth to an attacker
The list of firms you approach reveals intent. Salary notes reveal your negotiating position. Comments on why you are leaving can do real damage if they reach your current employer, especially while you are still under contract. A tracker puts all of this in one place, which makes it an efficient target. Four scenarios drove the design.
| Threat | What it means | Design response |
|---|---|---|
| Database breach | An attacker reads the server's storage | Records are encrypted in the browser before upload |
| Operator access | An insider reads user content | The server never holds the key to the content |
| AI exposure | Text leaves the application toward a model provider | Explicit consent per action, or the user's own API key from the browser |
| Code compromise | The operator, or an attacker, changes the code the user runs | Reduced surface and declared as a limit, not solved |
How the encryption works
Encryption uses WebCrypto only, with no third-party libraries. The password goes through PBKDF2-SHA256 with 600,000 iterations. The salt is derived from the email address, which lets the browser compute the result before it talks to the server. That is a trade-off: a derived salt is predictable, unlike a random per-user salt, so the work factor and the password policy carry the weight.
The output is split with HKDF into two independent keys. The first is an access key, which replaces the password toward the server. The password never travels, and the server stores only an argon2id hash of the access key. The second is a key-encryption key, which never leaves the browser.
Applications and files are encrypted with a random AES-256-GCM data key. Every record gets its own random 96-bit IV, and a context label is bound as authenticated data, so a blob cannot be silently moved from one record type to another. The server holds the data key only in wrapped form: one copy wrapped by the password-derived key, one wrapped by a key derived from a 160-bit random recovery code, shown once at registration. In the browser, the data key sits in IndexedDB as a non-extractable key. Scripts can use it but cannot read it. Accounts add an authenticator app as second factor, with ten recovery codes.
The cost is explicit. If you lose both the password and the recovery code, the data is gone. There is no reset by support, because there is nothing support could reset. I would rather say that at signup than let a user discover it later.
What passes in clear and what I cannot fix
End-to-end encryption claims are only as useful as their declared exceptions. Jobdossiers has three, each behind a consent.
The first is the address of a job posting, when the user asks the service to read the page. The server fetches it, and does not store or log it. The second is the text sent to the built-in AI. The browser decrypts what is needed and sends it to the server, which passes it to Infomaniak in Switzerland. Infomaniak states that it neither stores nor trains on the content, and the service keeps neither text nor result. That is the operator's statement, not an audit. The alternative is a personal API key from Anthropic, OpenAI, Google Gemini or Mistral: the key is encrypted in the browser and calls go from the browser to the provider, so the text never touches my servers. It does reach the provider in clear, under the provider's terms.
The third applies to Plus users who connect an external assistant through a read-only connector. The browser encrypts a reduced copy of the records with a key derived from a secret that only the assistant holds. When the assistant asks, the server decrypts the authorised fields for the duration of that request and returns them in clear to the assistant's provider. The user picks the field groups and a duration between one and 90 days.
Metadata stays visible: email address, application status, dates, ordering, the size of encrypted files and timestamps. Company, role, notes, contacts and file names sit inside the encrypted blob.
The limit I cannot remove is the fourth scenario. The server delivers the JavaScript. A malicious operator, or an attacker who compromises me, could ship a modified version that reads data as it is typed, including an API key. Client-side encryption protects stored data from a passive breach. It does not defend against an active compromise of the code path, and every browser-based design shares that limit. What I can do is shrink the surface: a short, auditable crypto file, a strict content security policy, no third-party dependencies and no third-party analytics. What I cannot do is prove to a user that the code received today is the code I reviewed. For API keys, my advice is a dedicated, revocable key with a spending cap at the provider.
◆ Key Takeaway
The useful question about a tool that holds your job search is not whether it says "encrypted". It is which threats it addresses, which exceptions it declares, and which limit it admits it cannot cover.
What to check in any tool that holds your job search
- Ask whether the vendor can read your records, and what an attacker would see after a breach of its storage.
- Find out where your text goes when AI features run, and whether you can choose that path or bring your own key.
- Establish what happens if you lose your credentials: a vendor that can always recover your data can always read it.
- Look for a stated limit of the encryption claim, including who delivers the code you run.
- Check for the baseline controls: a memory-hard password hash, a second factor, no third-party analytics and a minimal cookie set.
- Confirm that you can export everything in open formats and that deletion removes the data.
Payments open in January 2027 and will add a processor, so I will revise this threat model then, and again whenever a feature starts to touch data in clear. If you read the design and find a hole, tell me. That is how a threat model improves.