Security model
What durable-local protects, and what it does not.
This is not a footer. It is the definition of the product.
What durable-local provides
Persistence — one named application value survives close and reload, inside the boundary the browser calls "site data."
Nothing else.
What it does not provide
Confidentiality. JavaScript executing at the application's origin
can read every slot. Anything that runs in your page — the app's own
code, third-party scripts you loaded, browser extensions with content-
script access — can call open() and read your state. The library does
not encrypt values.
Integrity against XSS. If your page is XSS'd, the attacker's script
runs at the same origin as the library. It can open(), set(),
destroy(). The library will not stop them; nothing at the same origin
can.
Server-side durability. The state stays on this device. Losing the device loses the state.
Isolation between users on shared devices. Anyone who uses this browser profile can read what is stored.
Tamper-evidence. A user with DevTools open can rewrite records in
IDB directly. Application logic that trusts stored state must validate
it — that is why the library invokes validate() after every read.
The right shape for storing secrets
Do not use durable-local to store secrets. Not tokens, not passwords,
not encryption keys, not personal information the user would not want a
malicious tab to read. If you need to persist a secret in the browser,
use the Web Crypto API to hold the material as a non-extractable
CryptoKey and store its identifier, not the material itself.
That is exactly what @0xsarwagya/ghost does — the private key lives
inside a non-extractable CryptoKey, and no JavaScript can read it.
The library asks the browser to sign for it; the bytes never leave the
browser's key store. If you find yourself wanting to encrypt values
before putting them in durable-local, you almost certainly want
Ghost instead.
Why no encrypt: true option
Encryption where the key lives beside the ciphertext is theatre. A
malicious script that can call slot.value can also call the
decryption routine — the security ceiling is unchanged. The library
will never ship a flag that suggests otherwise.
If a future protocol version adds a real key-management model (backed by a non-extractable key that lives elsewhere), encryption becomes worth adding. Not before.
Threat model
durable-local is designed to be correct against these:
- Reload. State survives.
- Concurrent tabs. Writes serialize; no torn state.
- Failed writes. Previous value survives.
- Migration failures. Previous value survives.
- Corrupted stored values. Never returned as
T; typed error instead of silent corruption.
It is not designed to be safe against these:
- XSS. Nothing at the same origin can be.
- Malicious extensions with content-script access.
- Physical device access.
- A user reading your source code and rewriting IDB by hand.
If the value must survive any of those, the value is not one this library should hold.