← coffershield.com
CofferShield

Security Architecture Whitepaper

The cryptographic design, the trust boundaries, the threat model, and — at equal length — what this design does not protect you from.

Document version1.0
ApplicationCofferShield 1.0.0
Build reviewed98efa70a0f811c1f…
AudienceTechnical

This document describes how CofferShield protects data, on the assumption that its reader will want to check rather than believe. Every parameter stated here is a property of the shipped build and can be read out of it: the application's own code is one unminified, unobfuscated inline script, and the vault format is published in §5.3. Where a claim rests on something the reader cannot verify from the artifact — a CI secret, a hardware behaviour, a platform API — this document says so rather than asserting it.

What this document is not It is not an audit. No independent party has reviewed this design or this code, and the roadmap in §17 says when that is intended to change. It is not a proof of security; it is a description of a design, its assumptions, and its failure modes, written so that a reader can judge whether the assumptions hold in their own situation.

1Executive summary

CofferShield is a personal vault for the records a household needs and rarely has in one place: what it owns and owes, insurance, documents, passwords and recovery phrases, and an estate plan — who inherits, how each asset actually transfers, and which incapacity documents exist and where they are kept. It is sold once and installed on a computer. There is no account to create, no server to sign in to, and no copy of anything held by the vendor.

All of it lives in one file, encrypted with AES-256-GCM under a key that exists only while the application is unlocked, derived from a password only the owner knows.

Why offline

The decision not to build a server was a threat-model decision, not a cost one. A synchronising vault has to hold ciphertext somewhere its operator can reach, which creates four exposures that no amount of client-side cryptography removes:

Exposure a hosted vault carriesWhy it persists despite end-to-end encryption
A breach yields every customer's ciphertext at onceEncrypted blobs are still an offline-attack corpus. One incident produces millions of files that can be ground against forever, and the weakest passwords in the set fall first.
The operator can be compelledNot to decrypt, but to ship altered client code to a named user. Every browser-delivered or auto-updating vault has this property; the customer cannot detect it.
Metadata accumulatesEven a service that reads no plaintext learns who has an account, when they log in, from where, on what device, and how their vault grows.
The service is a dependencyIf it goes away, is blocked, or has an outage, so does access to the records — often at the moment they are needed.

Removing the server removes all four. It also removes real conveniences — synchronisation, sharing, server-side recovery, and the ability to push a fix — and §14 and §17 are honest about that trade. The exchange is deliberate: the failure modes that remain are ones the owner can see and control, rather than ones held by a third party on their behalf.

Security philosophy

  1. State the parameters. A design that has to be secret is not a design a reader can evaluate. Algorithms, iteration counts, key sizes and file formats are published here and are readable in the shipped file.
  2. Fail closed, and say when a control is not a control. Several mechanisms in this product are conveniences that look like protections — the session PIN, Windows Hello, the clipboard timer. Each is labelled as such in the interface and in §9 and §12, because a control the owner overestimates is worse than one they know is thin.
  3. Do not create secrets the owner did not ask for. No telemetry, no device identifier, no crash reports, no licence check. There is nothing to leak because nothing is collected (§11).
  4. The master password is the whole boundary. Everything else — the lock timer, the biometric shortcut, the decoy — sits inside that boundary or beside it. If the password is weak, none of it matters, which is why §6 spends more space on password strength than on ciphers.
THE WORLD Vendor and network No account, no server, no synchronisation, no telemetry What the vendor holds about you: nothing Optional, off by default: ticker symbols to a price provider the owner chooses (§10) DEVICE BOUNDARY — one computer the owner controls At rest vault.json · .coffer backups AES-256-GCM ciphertext indistinguishable from random Copyable by anyone with the file. Useless without the password. In memory, while unlocked the only place plaintext exists Decrypted records + data key discarded on lock and on quit Exposed to anything already running on this machine as you (§14). unlock
Figure 1 — Trust boundaries. There are two, and only one of them is enforced by cryptography. Everything to the right of the dashed line depends on the device itself being sound; §13 states that assumption plainly and §14 describes what happens when it fails.

2Security principles

These are the rules the implementation is held to. Each is stated with the mechanism that enforces it and, where the principle is only partly achieved, the gap.

PrincipleHolds?What enforces it, and where it stops
Local firstYes Every feature works with the network cable out. The one exception is price refresh, which is off until configured and degrades to manually entered prices.
Offline by defaultYes Three independent gates keep the price feature off in a new vault; the host has no HTTP client at all, so all egress is webview-side and confined by connect-src.
No cloud storageYes No storage code paths exist other than the local file, IndexedDB and memory. A backup can be placed on a cloud drive by the owner; that is their decision, and the file is ciphertext.
No user accountsYes There is no registration, no licence check, no activation call, and no identifier generated at install.
No central serverYes No CofferShield-controlled origin appears anywhere in the build, including in the CSP allowlist. There is nowhere for it to report to — though see §10.3 on what a policy of this shape does and does not close.
The owner holds the dataYes One file the owner can copy, move, back up or delete. The export format is documented and opens on either platform.
Encrypted by defaultYes There is no unencrypted mode and no partial mode. A vault cannot be created without a password of at least 12 characters.
Least exposureMostly The request payload for price lookups is enforced by an allowlist assertion, not by convention. The desktop host defines fifteen commands of its own, and the webview also holds the framework's default permission set — roughly a hundred built-in commands for window state, paths, events and images. §12.3 lists the fifteen and what constrains each. Nine touch the filesystem, and one of those constraints is still only partial.
Privacy by designYes Nothing is collected, so nothing is retained, so there is no retention policy to trust.
Zero knowledgeNot applicable The term describes a service that holds your ciphertext and cannot read it. CofferShield holds nothing, so the property is vacuous rather than achieved. Using the phrase would imply a service exists. See the note below.

On the phrase "zero knowledge" In the password-manager industry this describes a server that stores encrypted data it is unable to decrypt. It is a meaningful claim there, because there is a server and the claim constrains what it can do. CofferShield has no server, so the honest statement is not "our servers know nothing" but "there are no servers" — which is a stronger position and a different one. This document avoids the term because borrowing it would suggest an architecture that is not present.

A principle this product does not claim Defence against a compromised host. Some designs push key material into a hardware element so that malware on the machine still cannot extract it. CofferShield does not do this on either platform. The data key lives in the JavaScript heap of the application process while the vault is open, and anything running as the same user can read that process. §14 states the consequences.

3System architecture

One process, one file, one key hierarchy. The diagram below is the whole product: there is no component off the page.

Owner types a master password Key derivation — PBKDF2-HMAC-SHA-256 600,000 iterations · 128-bit random salt salt stored beside the vault, never secret Key-encrypting key (KEK) AES-256 · non-extractable · memory only unwraps Data-encrypting key (DEK) 256 random bits · never leaves memory ENCRYPTED VAULT — one AES-256-GCM ciphertext everything below is inside the single ciphertext Assets Liabilities Insurance Documents Passwords Estate Beneficiaries Incapacity settings, custom fields and your own types are in here too export Encrypted .coffer backup the same ciphertext, in a file the owner moves USB stick External drive NAS Cloud drive, if you like Not in this diagram no server no database no account no cloud storage and no code that could add one Held only in memory the master password, both keys, and every decrypted record Cleared on lock, on quit, and on any power loss. Never written to disk.
Figure 2 — System architecture. The password derives a key that unwraps a second key; only the second key touches your data. §5 explains why the split exists and what it buys.

3.1 Components

ComponentWhat it isSecurity role
ApplicationOne HTML file. The application's own code is a single unminified inline script; the file also carries a bundled copy of Mozilla's pdf.js, minified third-party code used only to draw document previews and never fetched at runtime. The shipped file is assembled from source fragments by a small splice script.Everything cryptographic happens here, through the platform's WebCrypto implementation. Nothing is loaded at runtime, so there is no supply chain at run time — only at build time.
Desktop shellA Tauri v2 host in Rust that owns the window, the file writes, the native dialogs and the Windows Hello prompt.The filesystem boundary. The webview cannot open a file on its own; it asks the host, and the host validates what it is asked (§12.3).
Platform webviewWebView2 (Chromium) on Windows, WKWebView (WebKit) on macOS.Supplies WebCrypto, and is the largest piece of code in the product that CofferShield did not write. It is also the only component that receives security updates independently — see §14.6.
Vault filevault.json in the per-user application data directory. One JSON envelope holding two ciphertext slots.The only durable artifact. Written atomically; owner-only permissions where the platform has a mode bit.
Backup files.coffer files wherever the owner puts them.Byte-for-byte the same ciphertext as the live slot, with a small cleartext header (§8.2).

3.2 The trust boundary, stated precisely

A boundary is only useful if both sides are named. CofferShield's cryptographic boundary is the master password, and it separates these two sets:

Inside the boundary (protected by the password)Outside it (not protected)
DataEvery record, document, password, recovery phrase, name, amount, note, setting, custom field and estate decision.The existence of the file, its size to within 64 KiB, and its modification time.
ThreatsSomeone who obtains the file, the disk, the backup, the cloud folder it was copied to, or the whole computer while it is locked.Someone who obtains the computer while it is unlocked, or who is already executing code on it as you.
TimeWhile the application is closed or locked.While the application is open.

4Threat model

The table below is the centre of this document. It is written so that the No rows are as easy to find as the Yes rows, because a reader deciding whether this product fits their situation needs the second list more than the first.

WHAT AN ATTACKER GAINS, BY WHAT THEY HAVE 1 · The backup file stolen USB stick, breached cloud folder, discarded disk Ciphertext only Must guess the password offline, at roughly 600,000 hash operations per guess. Learns the file exists and its size to the nearest 64 KiB. Defence: §6, password strength. Nothing else helps. 2 · The locked computer laptop stolen, seized at a border, left behind Ciphertext only Same position as level 1, plus a Windows Credential Manager entry if quick unlock was enabled — which is a copy of the data key, readable by anything running as you. Defence: §6, and leaving quick unlock off (§12.2). 3 · Code running as you malware, a malicious installer, an insider Everything, eventually Can log the password as it is typed, read the process memory while unlocked, or replace the application. No local vault design survives this. Nor does any hosted one, once the password is captured. 4 · The unlocked screen an open laptop, a shared screen Everything, now The vault is already open. Auto-lock (§9) shortens the window; it does not close it. Defence: lock the computer, not just the app.
Figure 3 — The escalation ladder. Cryptography covers levels 1 and 2 completely and levels 3 and 4 not at all. The design decision that matters is where the line sits, and it sits between the second box and the third.

4.1 The table

ThreatProtectedWhat actually happens
Lost or stolen laptop
device gone, vault closed
Yes The thief has ciphertext. Recovering it means guessing the master password against a 600,000-iteration KDF, offline. §6 gives the arithmetic. If quick unlock was enabled, see the qualification in §12.2 — the stored key changes this answer.
Stolen backup driveYes A .coffer file is the same ciphertext as the vault. Identical position to the row above. This is why backups can safely be left in places the owner does not fully control.
Cloud storage breach
a backup on Dropbox, iCloud, OneDrive
Yes The provider holds an opaque blob. There is no key on their side, no recovery mechanism, and nothing for a support agent to be socially engineered into releasing.
Vendor database breachYes There is no database. This row cannot be true of CofferShield in the way it can be of a hosted product, because the asset that would be breached does not exist.
Server compromise
including a compelled operator
Yes No server, and no update channel through which altered code could be delivered to a targeted user. §14.6 explains the cost of that second property.
Password reuse
your password leaked from another site
Yes The master password is never transmitted, so it cannot appear in someone else's breach unless you also used it elsewhere. Credential-stuffing has no endpoint to attack. Reusing the master password on a website removes this protection entirely.
PhishingYes There is no login page to imitate and no account to hand over. A convincing fake CofferShield website has nothing to collect. The residual risk is being tricked into installing a counterfeit application — which is a supply-chain problem, and §14.7 is candid that the unsigned Windows installer makes it a real one.
Network interceptionYes No vault data crosses the network at any point. With price refresh on, the only outbound content is ticker symbols and the owner's own API key, over HTTPS, to a host on a fixed allowlist (§10.2).
Ransomware
encrypts or destroys your files
Partly It cannot read the vault without the password. It can certainly encrypt or delete the file, which is a loss of availability, not confidentiality. An offline backup is the only defence and it is a complete one. Note that ransomware is code running as you, so §14.1 applies to anything it does while the vault is open.
Physical attacker, vault lockedYes Equivalent to the stolen-laptop row. Cold-boot and DMA attacks against a machine that was powered on with the vault open are a real class and are not addressed here; full-disk encryption with a pre-boot password is the mitigation, and it is the operating system's to provide.
Physical attacker, vault openNo The data is on screen. Auto-lock and lock-on-hide reduce the window (§9.2) but an attacker in front of an unlocked session has the vault.
KeyloggerNo Captures the master password as it is typed. Everything follows. No local application can prevent this, and one that claims to is describing an operating-system feature it does not control.
Memory-scraping malwareNo While the vault is open, the decrypted records and the data key are in the process heap. Keys are held as non-extractable WebCrypto objects and raw key bytes are zeroed after use, which raises the effort slightly; it is a speed bump, not a boundary.
Clipboard malwarePartly A copied password is cleared after a configurable delay, 45 seconds by default. That closes the window for an opportunistic clipboard reader; it does nothing against one that polls continuously. Windows clipboard history retains a copy the application cannot reach — the interface says so at the point of copying.
Remote-access trojanNo Equivalent to an attacker sitting at the keyboard, with the addition that they can wait for you to unlock. See §14.1.
Screen recording / shoulder surfingNo Secrets are masked until revealed and re-mask after twenty seconds, which is a defence against a glance rather than a camera. The window is not marked as capture-protected, so screenshots and screen-sharing show its contents; §17 lists this as candidate work.
Malicious or crafted backup fileYes A backup that has been altered will not decrypt: AES-GCM authenticates the ciphertext, so tampering produces a failure, not a wrong answer. Content arriving inside a valid backup is treated as untrusted input and is escaped and bounded on the way in — see Appendix B, which records that this was not fully true before this review.
Evil-maid firmware or bootkitNo An attacker who can modify the boot chain can replace the application. Secure Boot and full-disk encryption are the relevant controls and belong to the platform.
Nation-state adversaryNo An adversary who can compel a device, compromise a supply chain, or apply targeted implants defeats this design, as it defeats every consumer product. What CofferShield does remove is the bulk collection surface: there is no repository of customers to serve one order against, and no operator to serve it to. Targeted access remains possible; scalable access does not exist.
Legal compulsion of the ownerOut of scope The decoy vault (§7.4) exists for the case where someone is compelled to open the application. Whether it helps is a legal question, not a technical one, and it varies by jurisdiction. Nothing in this document should be read as advice on that point.

The one-sentence version CofferShield protects data at rest against anyone who obtains the file, and it does not protect a computer that is already compromised or already unlocked. If your threat model is the first, this design is a good fit. If it is the second, no vault product solves it and you need to fix the machine.

5Cryptography

Nothing here is novel. Every primitive is a standard construction from the platform's own cryptographic library, used in a documented mode, with parameters chosen conservatively. That is the intended impression: a personal vault is not the place to be interesting.

5.1 Primitives

PurposeConstructionParameters
Bulk encryptionAES-256-GCM256-bit key, 96-bit IV drawn fresh per encryption, 128-bit authentication tag
Key derivationPBKDF2-HMAC-SHA-256600,000 iterations, 128-bit random salt, 256-bit output
Key wrappingAES-256-GCMthe derived key encrypts the 32-byte data key as an ordinary message
IntegrityGCM authentication tagverified on every decryption; a failure is a failure, never a partial read
RandomnessThe platform CSPRNG via crypto.getRandomValues used for every key, salt, IV, padding byte, recovery key and generated password
Recovery key splittingShamir secret sharing over GF(28) threshold k of n, one polynomial per byte, information-theoretically secure below the threshold
Human-transcribable codesCrockford base32 with a Fletcher-16 tail no I, L, O or U, so a handwritten 1 or 0 cannot be misread; the checksum catches a typo before anything is attempted

Why PBKDF2 and not Argon2id or scrypt Argon2id is the better function. It is memory-hard, which is precisely the property that degrades a GPU attack, and if CofferShield could use it, it would. It is not available in WebCrypto, so shipping it would mean either a WebAssembly implementation carried inside the file — new code in the most security-critical position in the product, unaudited, with its own supply chain — or a native dependency that would have to be trusted equally on two platforms.

The judgement made here was that a well-reviewed platform PBKDF2 at 600,000 iterations is a better risk than an unreviewed memory-hard function that this project would be maintaining itself. 600,000 is the current OWASP recommendation for PBKDF2-HMAC-SHA-256 and matches what mainstream password managers use for the same primitive. The trade is stated so a reader can disagree with it: PBKDF2 parallelises well on a GPU, and that is the reason §6 asks for a longer password than a memory-hard design would need.

5.2 The key hierarchy

The password does not encrypt your data. It encrypts a key, and that key encrypts your data. This two-level structure is why changing the master password on a vault holding hundreds of megabytes of scanned documents is instantaneous, and it has a security consequence worth stating: the data key never changes, so anyone who captured the ciphertext before a password change can still open it if they later learn the old password.

Master password known only to the owner Recovery key 32 random bytes, printed once Quick unlock Windows only, opt-in PBKDF2, 600k, salted a fresh salt on every change KEK non-extractable wrapped DEK 48 bytes on disk decrypts decrypts its own separate copy DATA KEY (DEK) 256 bits · memory only a second copy of the same key, held by the OS credential store (§12.2) ENCRYPTS The vault body every record, document and password, as one blob Three doors, one key. Each path independently unwraps the same data key; none of them can produce it without its own secret.
Figure 4 — Key hierarchy. Three ways in, one key out. Adding a recovery key or enabling quick unlock adds a door; §14.4 treats that as the trade-off it is.

5.3 The vault record

A vault file is a small JSON envelope containing two slots of identical shape. Everything in a slot except the ciphertext is public by design — a salt and an IV are not secrets, and treating them as such would be a sign of a design that had not been thought through.

vault.json format: "coffer.vaultfile" · version: 2 · slots: [ … , … ]  —  the two slots are written in random order SLOT A SLOT B — byte-for-byte the same shape kdf iterations 600000 · salt, 16 random bytes, base64 public wrap the data key, encrypted under the password key · iv + ct 48 bytes rec  — present only if a recovery key was made the same data key, encrypted under the recovery key optional iv + ct the vault body: AES-256-GCM over a padded JSON document length-prefixed, padded with random bytes to a 64 KiB boundary Identical structure. Nothing in the file marks which slot is the real one and which is the decoy — see §7.4. Padding to a 64 KiB boundary means the file size reveals the vault's size only to the nearest bucket: adding a password, or ten, usually changes nothing observable. A four-byte big-endian length prefix records the true payload size inside the ciphertext, where an observer cannot read it.
Figure 5 — Vault file layout. The only secret in the file is the key you carry in your head. Everything else is published here.

5.4 Unlocking

OWNER APPLICATION WEBCRYPTO VAULT FILE password read the envelope, take the first slot derive a key from the password and that slot's salt — 600,000 iterations decrypt the wrapped data key wrong password → the tag fails → try the other slot, then report failure decrypt the body with the data key Check the canary inside the plaintext a slot that decrypts but is not ours is not accepted vault open — keys held in memory, nothing written Cost per attempt: 600,000 iterations. This application tries both slots; an attacker writing their own loop tries only the one they want.
Figure 6 — Unlock sequence. Both slots are attempted with the same password, which is what allows a decoy to exist without any marker in the file saying so.

There is no attempt limiting, deliberately CofferShield does not count failed attempts, delay retries, or wipe after n failures. It would be theatre. An attacker who has the file does not have to use this application to attack it — they write their own loop against the format published in §5.3. Attempt limiting only constrains someone who is politely using the front door, and the person you are worried about is not.

The real control is the KDF work factor, which applies to every attempt by anybody, in any tool. A wipe-after-n feature would add a way to destroy your own vault by mistyping, which is a genuine risk in exchange for an imaginary one.

5.5 Saving, and why changing the password is instant

EVERY SAVE Serialise the whole vault to JSON Pad with random bytes to a 64 KiB boundary Encrypt with the data key, a fresh IV each time Write to a temp file, flush, rename over the old one CHANGING THE MASTER PASSWORD Unwrap the data key with the old password Derive a new key from the new password and a new salt Re-wrap 32 bytes. The body is not touched. Clear any stored quick-unlock key, which predates the change
Figure 7 — Save versus re-key. A password change rewrites 48 bytes, so it takes the same time on a 2 MB vault as on a 200 MB one. The consequence is in §5.2: old ciphertext stays openable with the old password.

Two details in that diagram matter more than they look:

5.6 What the cryptography does not do

6The master password

Every other control in this document is secondary to this one. An attacker with your vault file has exactly one problem to solve, and this is it.

6.1 Why it cannot be recovered

The password is never stored, never transmitted and never derivable from anything on disk. What the vault holds is a salt and a ciphertext; there is no verifier, no hash of the password, and no hint. A correct password produces a key that decrypts the wrapped data key and passes the authentication tag. A wrong one produces a key that fails it. Nothing in that process can be run backwards.

This is not a policy that could be relaxed on request. There is no vendor-held key, no escrow, no support process, and no code path that would accept one. A "reset my password" feature would require a second copy of the data key held by someone other than you — which is precisely the property this architecture exists to avoid.

The consequence, stated once, plainly If you forget your master password and have not made a recovery key, the vault cannot be opened. Not by you, not by the vendor, not by anyone with a warrant. The data is gone. Write the password down and store it physically before entering anything real. A sealed envelope with your will is a good place. Your memory alone is not.

6.2 Entropy, and what the numbers actually mean

Password strength is a statement about how many guesses an attacker must make, and it is only meaningful against a stated attack rate. PBKDF2-HMAC-SHA-256 parallelises well on GPUs. The figures below use two reference adversaries:

These are order-of-magnitude figures derived from published benchmarks, offered so the arithmetic can be checked rather than trusted. Hardware improves; treat the right-hand column as the number that matters.

What you chooseEntropyIndividual, 105/sOrganisation, 107/s
A word and two digits~20 bitssecondsinstant
A memorable phrase from a book or song~25 bitsminutesinstant
Three random words from a 2,048-word list~33 bits~12 hours~7 minutes
Four random words from a 2,048-word list~44 bits~2 years~8 days
Four words from CofferShield’s own list 269 words, about 8 bits each~32 bits~1 hourunder a second
What CofferShield suggests — seven words plus a number~66 bits ~20 million years~200,000 years
A generated 20-character random string~110 bitsbeyond any projection worth writing down

Two things in that table matter. The first is that four words is a common recommendation, is fine for an account behind a rate limit, and is not fine for a file an attacker can copy and grind at leisure. The second is that “a random word” is not a fixed quantity: it is worth about eleven bits drawn from a 2,048-word list and about eight from CofferShield’s own short, deliberately plain one. That is the whole reason the built-in suggestion is seven words rather than four.

What the built-in generator produces Pressing Suggest one when creating a vault produces a seven-word passphrase from the application's own wordlist, with a two-digit number attached to one word — approximately 66 bits. The list is short and deliberately plain, which is why the count is seven rather than the four or five a larger list would need. The generator inside the vault, used for website passwords, defaults to a 20-character random string, and to five words if you switch it to phrase mode. A site password is guarded by that site’s rate limiting; the master password is guarded by nothing but its own length.

6.3 Choosing one

DoWhy
Use six or more random words, or accept the suggestionLength beats complexity against an offline attack. A long phrase of ordinary words is both stronger and easier to type correctly under stress than a short jumble of symbols.
Let the machine choose the wordsPeople asked to pick "random" words pick related ones, and a phrase drawn from a life is a phrase drawn from a small set.
Write it down and store it physicallyThe realistic failure of this product is not a broken cipher. It is a person who cannot remember a password they chose two years ago.
Never reuse it anywhereReuse re-imports every risk this architecture removed. A breach elsewhere becomes a breach here.
Consider a recovery key as well§7.5. It is a second door, so it must be stored like a deed rather than in a drawer — but it converts "the vault is gone" into "fetch the envelope".

The minimum accepted length is twelve characters. That is a floor against obvious mistakes, not a recommendation; twelve characters of ordinary text is well under 40 bits.

7Vault architecture

7.1 One boundary, not several

A common design puts different data classes in different containers — documents here, passwords there, settings in the clear. CofferShield does not: there is exactly one ciphertext, and everything is inside it. That choice costs some flexibility and buys a property worth more, which is that there is no list to audit of what happens to be unencrypted this release.

INSIDE THE CIPHERTEXT — one AES-256-GCM blob under the data key Records assets, liabilities, values, quantities, purchase history, your own fields Documents the file bytes themselves, base64 inside the vault — not a path to them Passwords and IDs logins, card numbers, identity numbers, wallet recovery phrases Insurance policies, premiums, beneficiaries, policy numbers and member IDs Estate heirs, shares, executor, transfer methods, what is kept where Incapacity agents named in your documents, their phone numbers, where originals are Settings and structure lock timings, clipboard delay, price-provider keys, hidden sections, custom fields, custom types, backup folder, and the net-worth history Then padded, then encrypted A four-byte length prefix, then random bytes out to the next 64 KiB boundary. Adding a password usually does not change the file size at all, so the file does not report your activity. The prefix lives inside the ciphertext, where it cannot be read from outside. OUTSIDE IT — plus three named in the caption The KDF parameters iteration count and a random salt. Public by design: a salt is not a secret and never was. The wrapped key and the IVs 48 bytes of ciphertext and two nonces. Useless without a password. A quick-unlock marker A one-byte flag saying the feature is on. Reveals that, and only that. Windows only. Light or dark appearance One word in browser storage, so the window does not flash white on open. A backup filename carries a date and a revision number in the clear, so a folder listing shows when you last saved.
Figure 8 — The encryption boundary. Three further items sit outside the ciphertext and are named elsewhere rather than in the panel: the presence of a recovery wrap on a slot, which identifies the real one (§7.4); each slot’s payload size to the nearest 64 KiB, which is not the same as the file’s size; and the device label and time of day in a backup envelope (§8.2). Everything you enter is inside the ciphertext.

7.2 Where the vault lives

TierWhereWhy
PrimaryA file in the per-user application data directory, written by the desktop hostSurvives an uninstall and survives "clear browsing data", neither of which is an acceptable way to lose a vault.
FallbackIndexedDB inside the webviewUsed by the portable edition, which has no host. A vault created by an older build in IndexedDB is lifted to the file on first run, verified, and only then removed from the old location.
Last resortMemoryIf both fail, the session still works and the owner can export. Nothing is silently lost.

Writes are atomic: a temporary file, flushed to the platter, then renamed over the previous one. Where the platform has a permission mode the file is created owner-only; on Windows it inherits the ACL of the application data directory, which this application cannot improve on without taking a dependency on security-descriptor code.

7.3 Documents

An attached document is stored inside the vault, not referenced from it. The bytes are encrypted with everything else, which is why an 8 MB per-file limit exists and why the interface discourages bulk scanning. Previewing a document decrypts it into memory and renders it from an in-memory blob; no temporary plaintext file is written to disk at any point in that path.

Printing is the exception, and it is not one this application can close: window.print() hands a rendered page to the operating system's print subsystem, which spools it to disk outside the application's control. §14.5 covers this.

7.4 The decoy vault

Every vault file contains two slots. One is yours. The other is created at the same moment, with a random 24-byte password nobody ever sees, unless the owner deliberately sets a decoy password — in which case that password opens a separate, harmless vault.

Both slots have the same field structure and are written in random order, and unlocking simply tries each in turn and takes the one that decrypts and passes its canary. A second slot is always present whether or not it is in use, so the presence of one answers nothing.

They are not indistinguishable to someone examining the file. Two things separate them. Size: padding rounds each slot to a 64 KiB boundary, not to a common size, so a real vault holding a scanned deed sits beside a decoy of a single bucket. The recovery wrap: if you have made a recovery key, only the slot it belongs to carries that field. The application warns about the first of these where you set a decoy password; this document states both.

What the decoy is and is not It is a way to open something when someone is watching. It is not proof that nothing else exists, and as the paragraph above says, an examiner holding the file can usually tell the two slots apart by size. Treat it as protection against being made to open the application, not against forensic examination of the file. Whether producing a decoy helps or harms in a given legal situation is a question for a lawyer in that jurisdiction, and this document takes no position.

7.5 Recovery keys, and splitting one

A recovery key is 32 random bytes generated on the device, shown exactly once, and never stored. What is stored is a third wrapped copy of the data key, encrypted under those bytes — structurally identical to the copy the password unwraps.

The same 32 bytes can instead be split into n shares of which any k reconstruct it, using Shamir secret sharing over GF(28). The property that makes this safe to hand to relatives is that fewer than k shares reveal nothing at all about the key — not "less information", literally nothing. That is information-theoretic, not computational: it does not depend on any assumption about the attacker's resources.

Recovery key 32 random bytes split Share 1 — a sister Share 2 — a solicitor Share 3 — an executor Share 4 — a safe Any two, together reveal nothing not a partial key, not a hint Any three, together rebuild the key exactly and open the vault The vault opens no single relative can do it alone Chosen when the shares are made: how many exist, and how many are needed. Each share is printed as a checksummed code, so a mistyped character is caught before anything is attempted.
Figure 9 — Threshold recovery. Illustrated as three-of-four. The threshold and the number of shares are both chosen by the owner.

A recovery key is a second door Anyone holding the printed sheet can open the vault without your password. It should be stored where you store a passport or a deed, not in a desk drawer, and it should be destroyed when replaced. Making one is a deliberate trade of confidentiality for availability, and it is the right trade for most households — but it is a trade.

8Backup architecture

The backup is not a second format. It is the live slot, copied out.

Live vault the current slot on this machine export restore .coffer file the same wrapped key and the same ciphertext, byte for byte opened by your master password WHEREVER YOU PUT IT USB stick in a safe External drive Network-attached storage A cloud drive, if you accept the trade CofferShield does not send it anywhere. Every one of these is a place you chose. Automatic backups, if enabled, write to a folder you pick, read the file back and compare the ciphertext before deleting any older copy, and keep the newest N. A write that cannot be read back never prunes anything.
Figure 10 — Backup and restore. Because the backup is the slot itself, there is no second password to lose and no second format to get wrong.

8.1 Properties

PropertyDetail
No cloud dependencyExport writes a file through a native save dialog. Nothing is uploaded, and there is no code that could upload it.
Cross-platformA backup written on Windows restores on macOS and the reverse. The format carries its own version and KDF parameters, so a file written by an older build opens in a newer one.
Opened by the master passwordNo separate backup password to forget. The file carries the same wrapped key as the vault, so the password that opened the vault when the backup was taken opens the backup.
Tamper-evidentModifying a backup makes it fail to decrypt. GCM does not produce a plausible-but-wrong plaintext.
Verified before pruningAutomatic backups read the file back and compare ciphertext before removing an older one, and never remove the last remaining backup.

A backup is frozen at the password of its day Because the wrapped key travels with the file, a backup taken before a password change still opens with the old password. That is convenient when you have forgotten a recent change and dangerous when you changed the password because it had been exposed. If you change your master password for a security reason, take a fresh backup and destroy the older ones.

8.2 What a backup reveals before it is opened

Three fields sit in the clear in the envelope so that a restore screen can describe a file before asking for a password: the time it was created, a revision counter, and a device label. The filename carries a date and the same counter. Someone with the file learns roughly when you last used CofferShield. They learn nothing about what is in it.

9Session security

Everything in this section is about the window between unlocking and locking. None of it is cryptography; all of it is about narrowing that window.

9.1 Key lifetime

launch nothing in memory password typed the password string exists for the length of the derivation unlocked both keys, and every decrypted record, live in the heap screen-locked keys still present — only the screen is covered locked or quit keys dropped, records dropped, interface emptied, clipboard wiped The exposure window Everything in §14 that begins "an attacker who is already running code" applies here and only here. Auto-lock exists to make this box narrow. Keys are held as non-extractable platform key objects: the application itself has no way to read their bytes back out. Raw key bytes are overwritten with zeroes immediately after wrapping or importing — with the two exceptions named in §14.2.
Figure 11 — Key lifetime. Non-extractable keys and zeroed buffers raise the effort of a memory attack; they do not prevent one, and §14.2 names two paths where a copy is deliberately kept alive.

9.2 The three lock states

LOCKED no keys in memory master password required UNLOCKED keys live, records decrypted this is the exposure window SCREEN-LOCKED keys still live a PIN uncovers the screen master password, recovery key, or Windows Hello Lock vault, quit, or idle with no PIN set idle timeout, or window hidden, when a PIN is set session PIN “Lock completely instead”, or quitting The distinction that matters: only the left-hand state has discarded the key. The right-hand state is a curtain, not a lock. The interface says exactly that on the screen-lock panel, because a person who believes otherwise will walk away from a laptop they should have shut.
Figure 12 — Lock states. Screen-locked is a convenience state and is described as one wherever it appears.

9.3 The controls, and how strong each one is

ControlDefaultWhat it does, and what it is worth
Auto-lock on idle5 minutes Discards the keys after inactivity. Click, keypress and pointer activity reset the timer; scrolling and mouse movement alone do not, so reading a long page can trip it. Selecting "Never" now genuinely means never — see Appendix B.
Lock when hidden5 minutes Starts a timer when the window is hidden or minimised, and cancels it if you come back. This is the control that covers walking away with the app behind a browser.
Session PINoff A convenience, not a security control. It covers the screen and is compared as a plain string in memory. It is never written to disk and cannot decrypt anything. With a PIN set, an idle timeout covers the screen rather than dropping the keys — which is a deliberate weakening of auto-lock in exchange for not retyping a long password all day. The interface says so.
Lock vault Immediate. Drops both keys and all decrypted data, empties the interface, wipes the clipboard, and clears any pending recovery key material.
Clipboard clearing45 seconds Overwrites the clipboard after the delay, and immediately on lock. Best-effort: an operating system can refuse a clipboard write from an unfocused application, and closing the app before the timer fires leaves the value in place. Windows clipboard history keeps a copy this application cannot reach.
Masked valuesalways Passwords, card numbers, routing numbers, identity numbers and security answers are masked until revealed, and re-mask automatically after 20 seconds. A recovery phrase is the exception: it stays visible until you hide it, because writing down 24 words against a timer produces errors.
Copy versus reveal In the passwords section, copying a secret schedules a wipe and copying an ordinary field does not — the distinction comes from the data model. Elsewhere it is chosen per button: a copied insurance policy number is not wiped, and its reveal has no 20-second timer.

Three honest notes on this section One: every control here operates inside the process. None of them helps against software that is already reading that process. Two: auto-lock protects against an unattended screen, which is a real and common risk, and against nothing else. Three: locking CofferShield is not the same as locking your computer, and the second is the one that matters when you leave the room.

10Offline architecture

The network is where most vault compromises come from, so the useful question is not "is the connection encrypted" but "how many bytes leave at all". For a default CofferShield installation the answer is zero: no request of any kind is made until the owner turns price sources on. This section describes that, and the optional exception in detail.

THIS COMPUTER CofferShield one process · one file · no background service Encrypted vault file never transmitted Backups you write to media you choose The host process has no HTTP client at all It declares five direct dependencies: the window framework, a file dialog, base64, and on Windows the credential store and the OS bindings. It constructs no HTTP client, and the framework’s own HTTP stack sits behind features this build does not enable. Treat that as a build-time supply-chain question (§14.8) rather than a hard wall. Every byte of egress is webview-side, confined by the policy in §10.3. NO DEFAULT EGRESS Never leaves the device records · amounts · balances · net worth passwords · recovery phrases · card numbers documents · names · beneficiaries · notes and the master password, above all May leave, only if you turn it on a ticker symbol  ·  an asset class  ·  a coin id plus a stock provider API key, if you set one up, over HTTPS, to one of four named providers Off in every new vault, search boxes included.
Figure 13 — Egress. The left column is what the product is; the right column is what can cross the line once the owner turns the feature on. Text typed into a symbol-search box goes to the same providers, under the same switches (§10.2).

10.1 Why an offline design reduces attack surface

Attack classRequiresPresent here?
Credential stuffing, brute force against a loginAn authentication endpoint Absent
Session hijacking, token theft, CSRFSessions and cookies Absent
Server-side injection, deserialisation, SSRFServer-side code Absent
Bulk data exfiltrationA repository of many customers Absent
Malicious update pushed to a targeted userAn update channel Absent — and §14.6 explains the price of that
TLS interception of vault contentsVault contents in transit Absent
Third-party script or CDN compromiseRuntime-loaded code Absent — nothing is fetched at runtime
Malicious dependency at build timeA dependency Present — see §14.8

10.2 The one exception, in detail

Price refresh updates the value of holdings that have a ticker or coin symbol, and it is off in every new vault. Stock prices additionally require a provider and an API key the owner obtained themselves; crypto prices go to CoinGecko, which works without a key, so that path is gated by the two switches rather than by three. The symbol-search box on a record form is gated by the same switches — it is a network request like any other, and it sends whatever you typed, which is not necessarily a ticker.

Your holdings quantities, values, names Build the request reduce each holding to its symbol, asset class and optional coin id An assertion, not a convention Every outgoing object is checked against an allowlist of exactly three keys. Anything else throws before the request is built. A future bug cannot quietly widen the payload. HTTPS GET, no body, abandoned after 10 seconds to one of: CoinGecko · Finnhub · Twelve Data · Alpaca What the provider learns •  which symbols you hold — not how many, not what they are worth •  your IP address, as with any web request •  your API key, which you created and can revoke A list of tickers is not nothing. If that matters to you, leave the feature off and type prices yourself — nothing else changes. Shown before every manual refresh the exact list of symbols about to be sent
Figure 14 — Price refresh. The payload restriction is enforced in code and fails loudly, which is the difference between a design intention and a control.

10.3 The content security policy

The application ships with a policy, and the desktop shell delivers the same policy as a header, with one addition — frame-ancestors, which a browser ignores in a meta element. Both are enforced when both apply, and a test fails if the two drift apart.

DirectiveValueEffect
default-src'self'Nothing loads from anywhere else.
script-src'self' 'unsafe-inline'Structural: the application is one inline script with no build step to hash against. This means the policy is not an XSS control — see the note below.
connect-src'self', the IPC scheme, and four named provider hostsThe one directive that constrains network exfiltration. No wildcard, and no remote host beyond those four. ipc: is a scheme-only source and is the local bridge to the desktop shell.
object-src'none'No plugins, no embeds.
base-uri'none'An injected <base> cannot re-point relative URLs.
form-action'none'Closes form submission, which is an exfiltration channel connect-src does not cover.
frame-ancestors'none'Set by the shell, where it can be enforced. A browser ignores this directive in a meta element.
style-src'self' 'unsafe-inline'Also structural: the interface carries several hundred inline style attributes, which WebView2 blocks without this. style-src-attr 'unsafe-inline' is set alongside it.
img-src'self' data: blob:Covers the inline icon and in-memory document previews. No remote images, so no pixel can be used as a beacon.
font-src'self' data:No remote fonts.
frame-srcblob:For in-memory previews. No remote frame can be created.

Being precise about what this policy is for With 'unsafe-inline' present, this CSP does not stop injected script from executing. Pretending otherwise would be the kind of claim this document is written to avoid. What it does is remove the value of executing: injected code cannot load a second stage, cannot post a form to an attacker, cannot open a connection to any host outside the allowlist, and cannot re-point the document's base. What it does not close is top-level navigation: no CSP directive covers that today, so script that could run could still send the window to an attacker's URL with data in the query string. The defence against injection itself is therefore output escaping in the application, which is tested — Appendix B records two places where it had failed and how they were closed.

11Privacy

Each statement below was established by searching the shipped build for the mechanism that would be required, not by consulting a policy document. A reader can repeat every one of these searches.

ClaimStatusHow it was established
No analyticsTrue The build was searched for every mainstream analytics and product-telemetry SDK by name. No match. There is no vendor-controlled origin in the CSP allowlist, so a beacon would be blocked by the shell even if one existed.
No telemetry or crash reportingTrue No error-reporting service is present. The host has no logging framework and writes no diagnostic file. A crash produces nothing that leaves the machine.
No advertising, no trackersTrue No third-party script, iframe, pixel or remote font. The application loads no external resource of any kind at runtime.
No accountTrue No registration, no licence check, no activation, and no identifier generated at install.
No synchronisationTrue No storage code path other than the local file, the webview store and memory.
No background uploadsTrue Seven network call sites exist in total, all in the price module, all reachable only when the owner has enabled and configured it. There is no background worker and no scheduled task.
No update checkTrue No updater plugin, no endpoint, no public key for signed updates, and no version ping. §14.6 treats this as a limitation as well as a property.

The practical consequence is that CofferShield has no data-retention policy, because there is no data to retain. There is no subject-access request to make and nothing to delete, since nothing was ever collected. That is a stronger position than a promise about how collected data is handled, and it is the whole reason for accepting the costs listed in §14.

12Platform security

12.1 The two platforms are not equivalent

WindowsmacOS
Webview engineWebView2 (Chromium), updated by Microsoft independently of this appWKWebView (WebKit), updated with the operating system
Vault locationPer-user application dataApplication Support in the user's library
File permissionsInherited from the parent directory ACL: your user, plus SYSTEM and administratorsOwner-only, set explicitly by the application
Biometric quick unlockAvailable — Windows Hello, opt-in, with the qualification in §12.2Not available — deliberately, see §12.4
Installer signingUnsigned — SmartScreen will warn (§14.7)Signing and notarisation are configured in the release pipeline (§14.7)
SandboxNoneNone — the App Sandbox entitlement is not claimed
Minimum versionWindows 10 1803, set by WebView2's own support floormacOS 11, declared in the bundle configuration and set by the CSS the interface relies on

12.2 Windows Hello quick unlock

When enabled, the operating system's credential store holds a second copy of the data key. Both enrolling one and retrieving one require the owner to pass a Windows Hello check first — face, fingerprint, or the device PIN Windows already accepts. The result is interpreted strictly: only an explicit success proceeds, and every other outcome, including an unrecognised one, is treated as failure.

OWNER COFFERSHIELD WINDOWS HELLO CREDENTIAL STORE unlock with Hello ask the OS to authenticate the person verified — and only this result proceeds now read the stored key the data key And the qualification that matters That prompt gates CofferShield's own path to the key. It does not gate the credential store itself: any program running as you can read that entry with no prompt at all. The app says so where you enable it. If Hello is unavailable no reader, not configured, disabled by policy — the feature reports off.
Figure 15 — Quick unlock. Treat this as a convenience that shortens a password you already chose, not as an additional layer of protection.

If your threat model includes malware on your own machine, leave quick unlock off Enabling it places a copy of the data key somewhere that any process running as you can read, with no biometric challenge. That trades a real reduction in security for a real gain in convenience. It is off by default, the interface states the trade at the point of enabling, and changing the master password clears the stored copy — because someone changing their password because they are worried about a laptop should not find that laptop still opens with a fingerprint.

12.3 The IPC boundary

No filesystem plugin and no dialog capability is granted to the webview, so it cannot open a file or raise a dialog on its own. What it has instead is fifteen commands defined by this application, plus the framework's default permission set — roughly a hundred built-in commands covering window state, paths, events, menus and images, among them one that reads an image from a path and one that toggles the inspector. The fifteen below are where this application's own validation lives.

Command groupWhat the webview can ask forConstraint in the host
Save a file"write these bytes, ask the owner where"A native save dialog. The webview never names the destination.
Vault read / write / deleteA key, not a pathThe key is stripped to letters, digits, hyphen and underscore and used as a filename inside the application data directory. Traversal and absolute paths are impossible by construction.
Backup writeThe owner's chosen folder plus a filename The filename must start with the application's prefix, end in .coffer, be a single path component, and carry no traversal or separator characters. Anything else is refused before a path is built. The folder is not constrained — it is whatever the caller passes, checked only to exist. §14.10.
Backup readNothing at allIt takes no arguments and reads only the file this process last wrote, so the caller can compare ciphertext before pruning.
Backup pruneA folder and a countDeletes files matching the backup naming pattern in that folder, never the last one. The folder is not constrained. §14.10.
Folder questionsA pathpick_folder raises a native picker and returns what the owner chose. Two more answer yes-or-no questions about a caller-supplied path; both are existence oracles and neither reads content.
Quick unlockEnrol, fetch, clear, availabilityEnrol and fetch both require a Windows Hello success first.
Window themeLight or dark title barCosmetic.

12.4 Why quick unlock is switched off on macOS

Doing it correctly on macOS means storing the key in the keychain with an access-control flag so that the Secure Enclave enforces Touch ID at retrieval — a materially stronger design than the Windows one described above. That code has never been compiled or run on a Mac by this project. A mistake there does not degrade gracefully; it either fails the build or, worse, stores the key with weaker protection than the interface claims.

So the feature reports itself unavailable on macOS and the master password is the only way in. That costs a Mac owner a convenience they never saw, and it avoids shipping a security claim that has not been executed. §17 lists doing it properly as planned work.

12.5 macOS entitlements

EntitlementWhy
com.apple.security.cs.allow-jitWKWebView runs JavaScriptCore, which needs JIT pages under the hardened runtime. Without it the window opens blank. This is the narrowest of the JIT-related exceptions; the looser allow-unsigned-executable-memory and disable-library-validation are not claimed.
com.apple.security.network.clientNeeded only if the owner turns on price refresh. Nothing else in the application touches the network.

Those two are the complete list. The App Sandbox is not claimed, which means the process has ordinary user-level filesystem access; that is a consequence of letting the owner keep automatic backups in a folder of their choosing without security-scoped bookmarks. It is a real reduction in containment and it is listed in §14.

13Security assumptions

Every security design rests on assumptions. Leaving them unstated is how a product ends up protecting something other than what its owner believed. These are CofferShield's, in the order that they matter.

Physical security of the device Yours. CofferShield cannot tell an owner from a thief holding the same unlocked laptop. not provided A sound operating system Patched, no malware, disk encryption on. Every layer below assumes this one holds. not provided A correct webview and platform cryptography WebCrypto and the platform CSPRNG are trusted to be what they claim. Updated by the OS vendor. inherited CofferShield: encryption at rest, key handling, session controls, output escaping This is the layer this document describes. It is the only one the product controls. provided A strong master password, and a backup that exists Yours again, and the two decisions that most determine whether any of the above matters. not provided
Figure 16 — Layers. Only the fourth band is CofferShield's work. The outer bands are assumptions, and a failure in any of them defeats the middle.
AssumptionWhy it mattersIf it does not hold
The computer is not already compromised The plaintext and the key exist in this process while the vault is open. Process memory is readable by other software running as the same user. Total loss. Everything in §14.1 applies. This is the assumption that carries the most weight.
The operating system is current The webview supplies WebCrypto and enforces the content security policy. A vulnerable webview undermines both. Depends on the flaw. A webview code-execution bug reduces to the row above.
The platform's randomness is sound Every key, salt, IV and generated password comes from the OS CSPRNG. Predictable randomness would make keys guessable regardless of password strength. Catastrophic and undetectable from inside the application. This assumption is shared by essentially all software on the machine.
The master password is strong and not reused It is the only secret protecting the file. §6 quantifies what "strong" means against an offline attack. The at-rest protection fails on a timescale set by the password, not by the cipher.
The device is physically controlled An unlocked screen is an open vault. Auto-lock narrows the window; it does not remove it. Anyone with hands on an unlocked session has the data.
The installer that was run was genuine A counterfeit build could do anything. Nothing in the file format authenticates the application to the owner. Total loss, silently. §14.7 is honest that the unsigned Windows installer makes this harder to verify than it should be.
Backups exist and are stored apart Encryption protects confidentiality. It does nothing for availability against theft, hardware failure or ransomware. The data is lost. This is by some distance the most common way people actually lose a vault.

14Security limitations

This section exists because a security document that only lists strengths is marketing. Each item is a genuine limitation of this design, stated without hedging.

14.1 A compromised computer defeats everything

If software is running on the machine as your user, it can log the master password as you type it, read the decrypted vault out of process memory while it is open, take screenshots, or replace the application with one that reports what you enter. No local vault can prevent this, and neither can a hosted one once the password is captured. Nothing in this document should be read as protection against it. Specifically, CofferShield does not defend against:

14.2 Memory is not protected

While the vault is open, decrypted records live in the JavaScript heap. Keys are held as non-extractable platform key objects, so the application itself cannot read a key's bytes, and raw byte buffers are zeroed immediately after wrapping or importing on the password and backup paths.

Two paths are exceptions, and are named here rather than glossed. Enrolling or retrieving a quick-unlock key moves the data key through a base64 string in order to cross the bridge to the host, and a JavaScript string cannot be erased. And opening the vault with a recovery key deliberately keeps the raw key in memory until a new password is set or the vault locks — so that the owner is not asked for the password they came to that screen because they had forgotten.

None of this stops a debugger, a memory-scraper or a crash dump. Managed runtimes also copy and relocate memory during garbage collection, so a guarantee of complete erasure is not available and is not claimed.

14.3 An unlocked session is an open vault

Auto-lock, lock-on-hide and the session PIN reduce the window in which that is true. None of them closes it. The session PIN in particular is a screen cover, not a lock — the key stays in memory while it is showing, and the interface says so where it is used.

14.4 Every extra door is a door

A recovery key opens the vault without the password. A quick-unlock enrolment puts a copy of the data key in the operating system's credential store. Both are opt-in, both are genuinely useful, and both enlarge the attack surface by exactly as much as they enlarge convenience. Neither is enabled by default, and both are described in the interface at the moment of enabling rather than in a footnote.

14.5 Printing leaves the boundary

The wallet card, the heir sheets, the emergency sheet and the recovery-key sheet are all designed to be printed, and printing is a plaintext operation by definition. Beyond the paper itself, the operating system's print subsystem spools the rendered page to disk at a location this application cannot reach or clean up. Print to a printer you control, and treat the paper as you would treat the contents.

14.6 There is no way to send you a fix

The absence of an update channel is a deliberate privacy property: no install can be counted, no user tracked, and no update endpoint hijacked to deliver code. It is also a real limitation. If a vulnerability is found in this application, there is no mechanism to reach you with a patch. You would have to learn of it independently and download a new build.

One component does update itself, and it is the largest: the platform webview. On Windows, WebView2 receives security updates from Microsoft independently of this application. The application layer does not.

14.7 Distribution integrity

PlatformStatusWhat this means for you
WindowsInstaller unsigned SmartScreen will show a warning and the publisher will read as unknown. More importantly, there is no signature to verify, so a substituted installer cannot be distinguished from the real one by inspection. Verify the published hash of the file you downloaded before running it. Code signing is the top item in §17 for a reason.
macOSConfigured, not asserted The release pipeline is set up to sign with a Developer ID and submit for notarisation, and will do so when the signing credentials are present. This document does not assert that any particular published build was signed; check that the copy you have opens without a Gatekeeper warning, which is the observable test.

14.8 Build reproducibility and provenance

Dependencies are declared as version ranges and there is no committed lockfile, so two builds of the same source may not be byte-identical. There is no build attestation and no software bill of materials. A reader cannot currently verify that a published binary was produced from the published source. §17 lists this.

14.9 Developer tools are enabled in release builds

The shipped desktop build can open a web inspector. This was a deliberate choice so that a rendering problem on a real machine can be examined rather than guessed at, and the cost is real: anyone with momentary access to an unlocked window can open the inspector and read the decrypted vault. It changes nothing about a locked vault, and it is one more reason the answer to §14.3 is "lock your computer".

14.10 The host's filesystem reach is narrowed, not eliminated

The backup commands validate the filename but not the folder: the folder is whatever the caller passes, checked only to exist. So script executing inside the webview could still write a file whose name matches the backup pattern into any directory the process can reach, or delete files matching that pattern from one. Reading is fully closed — the read-back command takes no argument and opens only the file the process itself last wrote.

Constraining the folder as well means the host remembering which folder the owner picked across restarts, which it does not currently do. Until it does, this is the residual surface, and it is why §12.3 says the constraint is partial. The same paragraph applies to the framework's built-in image-from-path command, which this application does not use but has not removed from the granted permission set.

14.11 What a determined, targeted adversary can do

An adversary who can compel a device, intercept a shipment, or place an implant on your machine defeats this product. That is true of every consumer security product, and a document that implied otherwise would be doing you a disservice. What this architecture removes is the scalable attack: there is no service to breach, no repository to seize, and no operator to compel. Attacks must be conducted one person at a time, against one machine at a time.

If any of the following is true, this product is not the right answer You need multi-user access with per-user permissions. You need an audit trail of who read what. You need to revoke access to data already shared. You need central administration or policy enforcement across a fleet. You need guaranteed recovery when an employee leaves. These are all real requirements, and they all require a server. CofferShield is a single-owner tool and does not pretend otherwise.

15Security best practices

Ranked by how much difference each makes, rather than by how easy it is.

Essential

Do thisBecause
Use a long master password — six or more random words, or accept the suggestionIt is the entire at-rest boundary. §6 has the arithmetic; the difference between four words and seven is the difference between days and millennia.
Write the password down and store it physicallyForgetting it is the most likely way you will lose this data, by a wide margin. A sealed envelope with your will.
Export a backup, and keep it somewhere elseEncryption does not protect against a failed drive, a fire, or ransomware. A backup does, and it is safe to leave in a place you do not fully control.
Never reuse the master passwordReuse re-imports every risk this design removes. A breach elsewhere becomes a breach here.
Keep the operating system patchedThe webview is the largest piece of code in the product and it is the platform's, not this application's.

Strongly recommended

Do thisBecause
Turn on full-disk encryption — BitLocker or FileVaultIt protects everything else on the machine, and it covers the print spool, temporary files and swap that this application cannot reach.
Lock your computer, not just the appAuto-lock protects an unattended CofferShield window. Only the OS lock protects an unattended computer.
Make a recovery key and store it like a deedIt converts "the vault is gone" into "fetch the envelope". Treat it as equal in value to the password itself, because it is.
Verify the installer before running itEspecially on Windows, where there is currently no signature to check. Compare the published hash.
Test a restore onceAn untested backup is a hope. Restoring on a second machine, once, converts it into a fact.

Consider, depending on your situation

Do thisBecause
Leave Windows Hello quick unlock offIf malware on your own machine is part of your threat model, the stored key is worth more to an attacker than the convenience is worth to you (§12.2).
Shorten auto-lock to one minuteOn a shared desk or in an office. The cost is retyping; the benefit is real.
Split a recovery key among several peopleIf continuity for your family matters more than the risk of a single holder acting alone (§7.5).
Keep the price feature offIf a third party learning which tickers you hold is a concern. Nothing else changes; you type prices yourself.
Keep documents out of the vaultIf you would rather the file stayed small and easy to back up frequently. Record where the originals are instead.

16Frequently asked questions

Can CofferShield recover my password?

No, and not as a matter of policy — as a matter of arithmetic. The password is never stored or transmitted, and the vault contains no verifier that could be attacked or unlocked from our side. If you made a recovery key, use that. If you did not, the data cannot be recovered by anyone.

Can hackers read my vault?

Not from the file alone. An attacker holding your vault or backup has AES-256-GCM ciphertext and must guess your master password against a 600,000-iteration KDF, offline. With a strong password, that is not feasible. An attacker who is already running code on your computer is in a completely different position — see §14.1, which is written plainly for exactly this question.

Can CofferShield employees see my data?

There is nothing for them to see. No account exists, no data is transmitted, and no server holds a copy. This is not a promise about internal access controls; it is the absence of anything to control access to.

What happens if your company disappears?

Your vault keeps working. It is a local file opened by a local application with no licence check, no activation and no server dependency. Nothing expires and nothing calls home. The format is documented in §5.3 and uses only standard primitives, so it can be read by other software if it ever needs to be.

Can I open my vault without internet?

Yes — that is the normal case. Every feature except optional price refresh works with the network disconnected, and price refresh degrades to the prices you last entered.

Can ransomware steal my vault?

It cannot read it without your password. It can certainly encrypt or delete the file, which is why an offline backup matters. Note that ransomware is code running as you, so while the vault is open §14.1 applies to anything else it chooses to do.

Is my data encrypted on my own disk, or only in backups?

Both, identically. There is no unencrypted state at rest. The live vault and the backup are the same ciphertext.

What if I lose the computer with the vault on it?

The thief has an encrypted file. Restore your backup on a new machine with the same master password. If quick unlock was enabled on the lost machine, read §12.2 — that changes the answer, and it is a reason to consider leaving the feature off.

Why is there no two-factor authentication?

Two-factor authentication protects an authentication event against a server. There is no server here and no login to intercept — the password is not checked against anything, it derives a key. A second factor would have to be stored on the device to be usable offline, which would make it a second thing on the same machine rather than a second factor. Quick unlock and the recovery key are the mechanisms in that space, and §14.4 is honest that each is a door rather than a lock.

Has this been independently audited?

No. Not by anyone. §17 states the intention to change that; until it does, this document is a self-description and should be weighed as one. Appendix B lists what a review conducted while writing it actually found, which may be more informative than the assurance itself.

Why should I trust a single-file HTML application?

Partly because you do not have to trust it blindly: it is one readable file, unminified, with no build step between the source and what runs. That is unusual and it is a deliberate transparency choice. It also has a real cost, documented in §10.3 — a single inline script means the content security policy cannot restrict script execution, only what executing script can reach.

17Future security work

Listed in the order they would most improve the product's security posture. Nothing here is a commitment to a date.

WorkWhy it matters
Code signing on WindowsThe largest single gap. Today there is no signature for a customer to verify and no way to distinguish a substituted installer by inspection. Every other item on this list matters less than this one.
Independent cryptographic reviewThe design in §5 has not been examined by anyone outside this project. A review of the key hierarchy, the slot format and the recovery-key construction is the assurance this document cannot provide about itself.
Independent penetration testingFocused on the IPC boundary and on injection paths into the interface, which is where this project's own review found the defects listed in Appendix B.
Reproducible builds and published hashesA committed lockfile, pinned toolchain and build attestation, so a published binary can be tied to published source.
Touch ID quick unlock on macOSDone properly, with the key held under Secure Enclave access control, this would be materially stronger than the Windows equivalent rather than a copy of it (§12.4).
Argon2id key derivationMemory-hardness is the property that most degrades the GPU attack in §6. Worth doing when it can be done without carrying an unaudited implementation inside the file.
Hardware security key supportA FIDO2 device holding a second factor for the data key. Genuinely useful, and genuinely hard to do without creating a way to lose the vault by losing a key.
Capture protection on the windowMarking the window so screenshots and screen-sharing show nothing. Straightforward; the open question is whether owners would rather keep the ability to screenshot their own records.
A signed security advisory channelNot an auto-updater — a place a customer can check, so that §14.6 stops being a dead end.

AAppendix A — Parameters at a glance

A.1 Cryptographic parameters

ParameterValue
Symmetric cipherAES-256-GCM
Initialisation vector96 bits, fresh from the CSPRNG on every encryption
Authentication tag128 bits, verified on every decryption
Key derivationPBKDF2-HMAC-SHA-256
Iterations600,000
Salt128 bits, random per slot, re-drawn on every password change
Data-encrypting key256 bits from the CSPRNG, wrapped under the derived key
Key extractabilityNon-extractable platform key objects; raw bytes zeroed after use, with the two exceptions in §14.2
PaddingRandom, to a 64 KiB boundary, with a length prefix inside the ciphertext
Recovery key256 bits, Crockford base32 with a Fletcher-16 checksum
Recovery key splittingShamir over GF(28), threshold k of n
Minimum master password12 characters
Suggested master password7 words plus a number — approximately 66 bits
Slots per vault2, identical in structure, order drawn from the CSPRNG at creation

A.2 Session and storage defaults

SettingDefaultRange
Auto-lock on idle5 minutes1 min – 1 hour, or never
Lock when hidden5 minutes1 – 15 min, or never
Clipboard clearing45 seconds15 – 90 s, or never
Masked value re-mask20 secondsfixed
Session PINoff4+ characters, memory only
Quick unlockoffWindows only
Price refreshoffopt-in, per provider
Automatic backupofffolder chosen by the owner
Maximum document size8 MB per filefixed
Network request timeout10 secondsfixed; the request is abandoned, not aborted

A.3 The build this document describes

ArtifactSHA-256
dist/index.html98efa70a0f811c1fc3ae51f64e369f8b7cd031e4dd23903b738eff2f30452155
src-tauri/src/main.rsab193884833c7365983a5d76a88a27a4b991e254e008249bdcce316377578de4
src-tauri/tauri.conf.jsone5803346b4409b54a4e8385ad2321cae9708682dd50b2975694d86fc447ee1b0
src-tauri/entitlements.plisteba132b18ca55caf8e8449717f61d88d381cb407557aa9f784a36de44394e745

Application version 1.0.0 · vault schema version 2 · backup format version 2. Automated test suite at the time of writing: 163 tests, 0 failures, run at the shipping 600,000 iterations as well as at a reduced count, and verified to behave identically on both platform webview engines.

BAppendix B — Findings from this review

This document was written by reading the shipped build rather than the intentions behind it. That exercise found defects. They are published here for two reasons: a reader deciding whether to trust a self-assessment is better served by seeing what it caught than by being told it was thorough, and a fixed defect that nobody mentions tends to come back.

All items below were found and fixed before this document was published, and each has a test that fails if it returns. Two rounds are recorded: the first from reading the application, the second from an adversarial pass over a draft of this document against the code, which is where B.2's last three entries came from.

B.1 The one that mattered

BEFORE — three weaknesses that composed into one chain 1 · A typed value a custom category name, or a location on a printed sheet reached the page as markup 2 · Script executes in the page holding the decrypted vault, with the host bridge in reach 3 · An unchecked filename the backup command joined a caller-supplied name to a folder; an absolute path replaced both Arbitrary file write anywhere the owner can write AFTER — the chain is broken in three independent places Escaped at the sink both sites fixed, and a test now checks every interpolated attribute in the built file Bounded on the way in names arriving in a restored backup are capped and stripped, not trusted because a form made them Validated at the boundary the host accepts only filenames of the shape it generates itself; reads take a folder and a name Plus a policy that removes the value of executing at all (§10.3) Any one of these fixes would have broken the chain. All four are in place, because a chain that needs every link is a chain that only needs one mistake to come back.
Figure 17 — The chain, and how it was closed. No exploitation is known; it was found by reading the code for this document, not by an incident. §14.10 states the part of the third link that is narrowed rather than removed.
FindingEffectFix
Two output-escaping failures A custom insurance category name reached a tooltip attribute unescaped, and a "where things are kept" location reached the printed heir sheet unescaped. Both are values the owner types, and both can also arrive inside a restored backup. Escaped at both sites. A test now scans the built file for any interpolated title attribute that is not escaped.
Unvalidated backup filename in the host The command joined a caller-supplied filename to the owner's chosen folder. An absolute path discards the folder entirely, and traversal escapes it a segment at a time. The host now accepts only filenames that start with its own prefix, end in .coffer, are a single path component, and carry no traversal or separator characters. Five unit tests in the host cover that validator directly, including both of the shapes above; a test in the application suite asserts the commands call it.
Arbitrary file read in the host The read-back command took a full path and read whatever was there. It now takes no argument at all and opens only the file this process last wrote. There is no argument shape left to abuse. The write and prune commands still take a folder that is not constrained — §14.10 states what that leaves open.
An unused command in the IPC surface A directory-listing command was registered and never called. Removed. An unused command is still a reachable one.

B.2 The others

FindingEffectFix
Enrolling a quick-unlock key required no consent Retrieving the stored key required Windows Hello; replacing it did not. One call could substitute the saved key. Enrolment now requires the same check as retrieval, before anything is stored. It also means nobody enrols without first proving the reader works.
The application shipped without its own CSP The desktop shell delivered a policy; the file opened directly in a browser had none. The policy now ships in the file as well, and the two are tested to agree. Both gained object-src, base-uri and form-action, which close channels connect-src does not.
"Auto-lock: never" locked anyway A stored zero was read as "unset" and silently replaced with five minutes. The setting screen was describing behaviour that did not occur. Zero is now a choice. The failure was in the safe direction; a setting that lies is still a defect.
A claim about hardware the build does not use An unreachable branch of the interface stated that the key was held in the macOS Secure Enclave. Quick unlock is disabled on macOS, so no user could see it — but the string was there. Removed, and a test fails if the phrase reappears in a build that does not implement it.
A stale ciphertext left behind after migration Lifting a vault from the browser store into a file did not remove the original, leaving a second copy ageing in the webview profile under whatever password was current when it was written. The file is read back and compared before the old copy is removed, so a half-finished migration never destroys the original.
The suggested master password was too short for an offline attack The wordlist is short and friendly — about eight bits a word — and the suggestion used five words, giving roughly 49 bits. That is inside reach of a well-funded attacker for a high-value target. Seven words, roughly 66 bits. A test recomputes the figure from the live wordlist and fails if either the list or the count moves the result below 60 bits.
A symbol search reached the network with prices switched off The equity search branches were gated behind a provider and a key. The crypto branch was not, because CoinGecko needs neither — so typing in the "Search coin" box on a record form sent that text, whatever it was, to a third party in a vault where price refresh had never been turned on. Gated on the same switches as every other request, and given the same timeout. A test drives the real module with a fetch stub and fails if any call is attempted while prices are off.
Slot order came from Math.random The order of the real and decoy slots is presented as something an examiner cannot exploit, so it should not have come from a generator that makes no such promise. Drawn from the platform CSPRNG, like every other random value in the product.
The interface recommended a weaker password than this document does The create-vault screen suggested "four or five unrelated words" while §6 calls four words inadequate for a file that can be copied. The screen now says six or more, and explains why in one line.

B.3 Known and not changed

These were examined and left as they are. Each is a judgement rather than an oversight, and each is documented in the body of this whitepaper so that a reader can disagree.

ItemWhy it stands
Developer tools enabled in release buildsDiagnosing a rendering fault on a real machine is worth more than the marginal protection removing them would give against someone who already has an unlocked window. §14.9.
No attempt limiting on the unlock screenIt would constrain only an attacker politely using this application, while adding a way to destroy your own vault by mistyping. §5.4.
PBKDF2 rather than Argon2idA reviewed platform primitive beats an unreviewed in-house one in the most critical position in the product. §5.1, and it is on the roadmap.
The window is not capture-protectedIt would also stop owners screenshotting their own records. §17 lists it as an open question rather than a decision.
Windows file permissions are inheritedImproving on the directory ACL would mean taking a dependency on security-descriptor code to protect a file that is ciphertext. §7.2.
The backup folder argument is not constrainedConstraining it means the host remembering the folder the owner picked across restarts. Worth doing; not done. §14.10 states the residual reach rather than leaving the reader to find it.

CAppendix C — Verifying these claims

Most of this document can be checked without trusting it. The application is a single file of readable source, so the following are not thought experiments.

Read the source The app’s own code is one unminified script. Skip the bundled PDF reader above it; the crypto core is ~175 lines. Search for the algorithm names in §A.1 and read what surrounds them. Watch the network Run the app behind a packet capture or a proxy for a session. With price refresh off, the expected result is no packets at all. Inspect the file Open the vault file in a text editor. You should see the envelope in §5.3 and base64 noise. Nothing you typed into the app should be findable in it. Pull the cable Disconnect entirely and use the product for a week. Everything except price refresh should behave exactly as it does online.
Figure 18 — Four checks. None requires special tooling, and the third one takes a minute.

C.1 Specific things to look for

Claim in this documentHow to check it yourself
600,000 PBKDF2 iterationsOpen the vault file and look for "kdf":{"it":600000. The count is stored in the clear in each slot, because it has to be.
AES-256-GCM with a fresh IVSave twice without changing anything. The slot's top-level iv changes both times, and so does ct. (A slot has up to three iv fields; the other two belong to the wrapped keys and do not change on a save.)
Padding to 64 KiBNote the file size. Add a password. In most cases the size does not change.
Two slots always presentCount the entries in the slots array. There are two, whether or not you set a decoy password.
Nothing plaintext at restSearch the vault file for a distinctive string you entered. It is not there.
No telemetrySearch the application file for the name of any analytics product you can think of, and watch the network as above. With price sources off, nothing should appear even while you type into a symbol-search box.
The CSPIt is a meta tag in the head of the application file, and the same policy appears in the desktop configuration.
Backups are the same ciphertextExport a backup and compare its ct field with the live slot's. They match.

C.2 What you cannot verify from the artifact

Reporting a security issue If you find something in this design or this implementation that is wrong, we would rather hear it than not. Please include what you did, what you expected, and what happened, and give us a reasonable window to fix it before publishing. Given §14.6, please also tell us how you would like to be told when it is fixed. Contact: security@coffershield.com.

CofferShield · Security Architecture Whitepaper · Version 1.0 This document describes a design, its assumptions and its limits. It is not an audit.