Summary
stash env and stash auth login can resolve different keysets. EQL v3 index terms (hm / bf / op) are keyset-specific, so data encrypted under one keyset and queried under another is decryptable but completely un-searchable — every search returns 0 rows, with no error anywhere.
This is a silent-data-corruption-class footgun: nothing fails, nothing warns, and the data looks correct at rest and on decrypt. Only the search results are wrong.
Source
rc.3 skilltester run (2026-07-19/20), finding F4 — one of four GA blockers. Hit on the supabase-edge surface. The assessor reproduced the mechanism directly: the same plaintext "Netflix" yielded hm=f5a3… as stored, but hm=587b… when a fresh query term was minted under the other keyset.
Verified in tree
The two credential paths genuinely differ:
stash auth login binds the device to the workspace's default keyset — stated in packages/cli/src/cli/registry.ts:270: "Your device is bound to the workspace's default keyset, so later…".
stash env (packages/cli/src/commands/env/index.ts:40-55) mints a new ZeroKMS client via POST {zerokms}/create-client, then an access key via POST {cts}/api/access-keys. Its docblock covers workspace CRN, client id/key, access key, and the member role — keyset selection is never mentioned, so the minted client's keyset is whatever create-client assigns rather than the workspace default the device is bound to.
So the two commands are documented to bind to different things, and nothing reconciles them.
Impact
Proposed fix
Two independent halves, either of which removes the silent failure:
stash env mints against the workspace default keyset — or fails loudly when it cannot, rather than minting a client on a different one.
encryptQuery signals a keyset mismatch instead of returning terms that match nothing. A query term minted under a keyset that does not match the column's stored terms should be an error, not an empty result set.
(2) is the more durable guarantee — it catches every route to the mismatch, not just the CLI one.
Notes
Adjacent but not a duplicate of #561 (allow passing a keyset to encrypt/decrypt operations, not just at init), which is about the API surface for selecting a keyset. This issue is about two CLI paths silently disagreeing on which keyset is in play, and the failure being invisible.
Summary
stash envandstash auth logincan resolve different keysets. EQL v3 index terms (hm/bf/op) are keyset-specific, so data encrypted under one keyset and queried under another is decryptable but completely un-searchable — every search returns 0 rows, with no error anywhere.This is a silent-data-corruption-class footgun: nothing fails, nothing warns, and the data looks correct at rest and on decrypt. Only the search results are wrong.
Source
rc.3 skilltester run (2026-07-19/20), finding F4 — one of four GA blockers. Hit on the
supabase-edgesurface. The assessor reproduced the mechanism directly: the same plaintext"Netflix"yieldedhm=f5a3…as stored, buthm=587b…when a fresh query term was minted under the other keyset.Verified in tree
The two credential paths genuinely differ:
stash auth loginbinds the device to the workspace's default keyset — stated inpackages/cli/src/cli/registry.ts:270: "Your device is bound to the workspace's default keyset, so later…".stash env(packages/cli/src/commands/env/index.ts:40-55) mints a new ZeroKMS client viaPOST {zerokms}/create-client, then an access key viaPOST {cts}/api/access-keys. Its docblock covers workspace CRN, client id/key, access key, and the member role — keyset selection is never mentioned, so the minted client's keyset is whatevercreate-clientassigns rather than the workspace default the device is bound to.So the two commands are documented to bind to different things, and nothing reconciles them.
Impact
stash envcredentials, query with astash auth loginprofile (or vice versa) → all searches silently return 0.wasm-inlinecannot read~/.cipherstash(see wasm-inline has no auto/dev-profile auth strategy — credential-free local dev impossible on WASM #663), so rawCS_*fromstash envis the only option — meaning the mismatch is easy to hit by following the documented flow.Proposed fix
Two independent halves, either of which removes the silent failure:
stash envmints against the workspace default keyset — or fails loudly when it cannot, rather than minting a client on a different one.encryptQuerysignals a keyset mismatch instead of returning terms that match nothing. A query term minted under a keyset that does not match the column's stored terms should be an error, not an empty result set.(2) is the more durable guarantee — it catches every route to the mismatch, not just the CLI one.
Notes
Adjacent but not a duplicate of #561 (allow passing a keyset to encrypt/decrypt operations, not just at init), which is about the API surface for selecting a keyset. This issue is about two CLI paths silently disagreeing on which keyset is in play, and the failure being invisible.