Staging — blog preview only.
Skip to content

XSS steals sessions elsewhere; here keys are non-extractable

Scheduled

8 min read By NT²

A vault that advertises invincibility is selling theater. NT² names the residual risks—XSS while unlocked, a stolen unlocked device, a hostile extension—and designs so those failures do not also become password oracles or exportable key dumps.

XSS steals sessions elsewhere; here keys are non-extractable

Claim: residual risk is part of the product promise

Most “secure vault” marketing stops at a comforting sentence: your data is encrypted, so you are safe. That sentence hides the interesting half of the problem.

Encryption at rest does not erase the unlocked session. While a vault is open, something in the page can decrypt. Cross-site scripting (XSS) in an ordinary web app often steals a session cookie or a bearer token—portable credentials an attacker can replay from another machine. Device theft with an unlocked laptop often means full access until the OS locks. A malicious browser extension with script access to the origin can do whatever the page can do.

NT² Vault does not pretend those classes of failure vanish because we say “zero-knowledge.” The claim is narrower and more useful:

We design so that an unlocked-session failure does not also become an exportable key dump, a provider password reset, or a cloud-side guessing oracle—and we say plainly what still hurts.

Elsewhere, XSS steals sessions. Here, vault AES keys are non-extractable CryptoKey handles in memory. That difference matters. It is not immortality.

Constraint: browsers share one JavaScript world with attackers

Three constraints force honesty.

First, same-origin script is the vault. If an attacker runs JavaScript in the unlocked vault page—via a content injection bug, a compromised dependency that ships into the origin, or a hostile extension that injects into the page—they share the same Web Crypto world the product uses. They can call the APIs the page can call. Non-extractable keys (Web Cryptography API) refuse exportKey, so raw AES bytes are harder to scoop into a pastebin. They do not prevent encrypt / decrypt while the handle is live. XSS while unlocked remains a serious bug. The design shrinks exfiltration of the key material itself; it does not forgive shipping third-party analytics into the vault origin.

Second, physical access beats crypto while the session is warm. A stolen phone with an unlocked vault, a laptop left open at a café, or a roommate who sits down before idle clear fires can read the screen and use whatever the UI exposes. Auto-lock shortens the window. It does not invent a secure enclave inside every browser, and it does not replace locking the OS.

Third, the edge must stay blind even when the client is compromised. If a client breach somehow also becomes “ask the server for salt, verifier, or a password reset,” the attacker gains a second surface: cloud-assisted guessing or support-desk recovery. The constraint cuts both ways: master password never leaves the browser; KDF salt and password verifier stay on the device; the Workers API authenticates identity without holding unlock ingredients. Client compromise is still catastrophic for that device’s unlocked window. It must not upgrade into a provider-controlled decrypt path.

These constraints collide with a familiar product instinct: minimize friction, maximize “remember this device,” and treat extensions as free distribution. For a password vault, those instincts widen the blast radius.

Design: session bounds, non-extractable keys, blind edge

The threat model we optimize for is not “no one ever runs script in the page.” It is “when they do, or when the device is stolen unlocked, the failure mode stays local and time-bounded—and the architecture refuses to amplify it.”

ThreatWhat still works against youWhat the design refuses to add
XSS / injected script while unlockedUse live CryptoKeys; read decrypted UI state; call vault APIs the page can callExportable vault AES keys; third-party scripts on the vault origin; silent restore of keys after refresh
Device theft / shoulder surfing while unlockedRead the screen; operate the unlocked UI until lock“Stay unlocked for days” cookies that rehydrate AES material; treating PWA install as continuous trust
Malicious extension with page script accessSame class as XSS for the origins it can touchPretending extension hygiene is optional chrome; shipping tracking SDKs that invite more script into the origin
Server / edge compromiseCiphertext, public identifiers, metadata the product already stores blindlyMaster password, KDF salt, password verifier, or a support reset that reconstructs unlock

Session policy is the client half of that table. Unlock derives or reconstructs a vault AES key with extractable: false, holds it in in-memory application state, and clears it to null on explicit lock, roughly five minutes without input, hard refresh, and tab close. Durable storage keeps ciphertext and unlock ingredients—not a ready-to-use key substitute. That story is deepened in Auto-lock is a memory hygiene problem; here it is the XSS and theft mitigator: shorten the live-handle window, refuse export, refuse silent re-entry.

The edge half is refusal of oracles. Salt and verifier stay on the device (The KDF salt stays on your device). There is no provider password reset (No password reset, by design). Cloud features authenticate a cryptographic vault identity; they do not receive the material needed to test master-password guesses. A compromised Worker should see ciphertext and blind account metadata—not a decrypt button.

flowchart LR
  subgraph client [Device]
    MP[Master password]
    Key[Non-extractable CryptoKey]
    CT[Local ciphertext]
    MP -->|derive on unlock| Key
    Key -->|decrypt while unlocked| CT
  end
  subgraph edge [Edge]
    Blind[Ciphertext + public ids]
  end
  CT -.->|optional sync ciphertext only| Blind
  MP -.-x|never| Blind
  Key -.-x|never leaves memory| Blind

Malicious extensions sit awkwardly between “XSS” and “physical access.” Chromium and other browsers grant extensions powerful privileges; some can inject script into pages the user trusts. NT² cannot rewrite the browser’s extension model. What we can do is keep the vault origin lean (no analytics widgets, no heavy third-party UI CDNs), keep keys non-extractable and short-lived, and tell users that a hostile extension with script access to the vault origin is effectively XSS. Extension review, OS updates, and not running untrusted add-ons remain user-side controls. Architecture does not erase them.

Trade-off: honesty costs comfort, and residual risk stays named

Naming residual risk costs marketing smoothness. It is easier to say “military-grade encryption” and stop. We refuse that stop.

Users who want thirty-day unlock will find the product stubborn. Users who refresh mid-edit unlock again. Users who install every extension that promises “productivity” still take a risk we cannot cryptographically delete. Reviewers who want a threat model that ends with “therefore safe” will be disappointed: XSS while unlocked can still decrypt; theft while unlocked can still read; JavaScript memory is not a hardware security module.

What we get back is a failure mode that matches the brand promise. When the client is wrong, the edge does not become a second vault owner. When the session ends, the live key is gone—not parked in sessionStorage as a string-shaped secret. When an attacker has script in the unlocked page, they still cannot casually exportKey the vault AES material for offline reuse elsewhere. That is a smaller blast radius, not a magic shield.

There is a related process trade-off. Agents and humans shipping vault code can always “helpfully” reintroduce extractable keys, a forgot-password email, or a salt escrow “just for recovery.” The product’s threat model only holds if those patches are blocked. That is why security veto is a role with authority—not a vibe in chat—see Security veto is a role, not a vibe.

What we refuse

Architecture is clearer when the refusals are explicit.

We refuse extractable vault AES keys in the unlocked session. If the browser can export the key, same-origin script can too.

We refuse treating XSS as “solved” by encryption at rest. Ciphertext on disk does not protect an unlocked memory handle. Mitigations are short sessions, non-extractable keys, and a lean origin—not slogans.

We refuse provider password reset and cloud-held unlock oracles. A client compromise must not upgrade into “email support for a new key that opens old ciphertext.”

We refuse third-party tracking and widget scripts on the vault origin that widen the script surface an attacker or dependency can abuse.

We refuse marketing invincibility. Device theft while unlocked, malicious extensions with page access, and XSS while unlocked remain real. Auto-lock and non-extractable keys shrink windows and exfiltration shapes; they do not delete the need for a locked OS, careful extensions, and a master password that is not reused from a breach dump.

We refuse “remember this device” rehydration of live AES material so unlock friction never becomes silent re-entry.

These refusals are the client-and-edge reading of Null Trust²: what we cannot do to your vault even when it would be convenient—for support, for growth, or for a smoother demo. That naming story lives in Null Trust² — what the name means.

Residual risk, named on purpose

A useful threat model ends where the product’s power ends.

NT² can keep the master password off the wire, keep salt and verifier on the device, keep vault keys non-extractable and out of durable storage, clear them on idle and refresh, and keep the edge blind to plaintext. NT² cannot make an unlocked browser tab immune to injected script, cannot stop a thief who uses an unlocked UI before auto-lock, and cannot police every extension a user installs.

Elsewhere, XSS steals portable sessions. Here, the live secret is a non-extractable handle with a short lifetime—and the architecture refuses to hand the attacker a second key via the cloud. That is the design. It is also the limit.

For memory hygiene detail, read Auto-lock is a memory hygiene problem. For salt placement, The KDF salt stays on your device. For recovery honesty, No password reset, by design. For the brand constraint behind the refusals, Null Trust² — what the name means. For how those refusals stay shippable under agent velocity, Security veto is a role, not a vibe.

If that threat model matches how you want a private vault to fail—narrowly, locally, without a provider back door—you can try NT² Vault or read more at nt2.me.

Last updated 2026-10-29

Related stories