Decide whether the OAuth signing key should be sealed under the vault DEK #166
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lz/agent-nexus#166
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spun out of #151, where this came up in review and was deliberately left as a decision rather than a silent default.
What ships today
nexus/src/lib/server/oauth/jwks.tsgenerates an EC P-256 signing key once and persists it in themetatable as plaintext JSON. It is not sealed under the vault DEK, unlikeconnections.encrypted_tokenandrepo_env_vars.encrypted_value.It is in
metarather thaninstance_settingsfor a reason that is not in question:listInstance()returns every instance-scoped setting, so a setting-shaped key would be served byGET /api/settings/instanceand rendered in the Settings panel.metais enumerated by no route.The exposure
Whoever can read that row can forge arbitrary access, refresh and ID tokens, for any scope and any account, indefinitely. That is strictly worse than lifting individual already-scoped tokens out of
oauth_payloads— which are also plaintext, and which #151's spec now documents as such rather than claiming otherwise.So the honest current threat model is: raw database access is game over for OAuth, and the mitigation is filesystem and backup hygiene, not storage-layer hashing.
Why it was not simply sealed
Sealing it under the DEK ties OAuth token issuance and refresh to the vault being unlocked. That breaks a property the MCP design treats as deliberate: the OAuth endpoints sit outside the cookie gate on purpose (
src/server.ts's dispatcher never consultslocals.masterKeyfor provider paths), so a background MCP client keeps working across a Nexus restart without the operator reopening a browser and typing a passphrase.That is a real trade-off, not an oversight:
Done when
A decision is made and written down — in the spec, with the reasoning, whichever way it goes. If the answer is "leave it", that is a legitimate outcome and the value of this issue is that the trade-off was chosen rather than defaulted into.
Worth deciding before Nexus instances are exposed with real MCP clients attached, because changing it later invalidates every issued token.