Repository navigation
Seal copilot own API keys under the owner's key passphrase - #166
Merged
Merged
Conversation
copilot_settings.anthropic_key / openai_key / elevenlabs_key were AES-GCM under the server env key COPILOT_KEYS_SECRET, so anyone with the box could open every user's BYOK keys. They now use the seal v2 pieces from #165 (same key passphrase and user_key_seals row as the YouTube token): - Saving seals each key to the owner's public key (v2:), 409 before a key passphrase is set; the settings page can set one (recovery key shown once). - Keys open only for a meeting the owner unlocked: Start sends the data key derived in the browser/desktop (never the passphrase); the private key is held in memory under copilot:<user>:<session> with a TTL and dropped when the copilot stops, the meeting ends, on Lock, or on restart. - Locked keys mean free models only, never our paid provider in their place; the panel shows an unlock box (also mid-meeting after a restart). - Legacy v1 values are never used for provider calls; they are re-sealed once in the owner's own request (key setup/unlock, copilot settings, start) and overwritten in place. LEGACY_KEY_MIGRATION=off is the cutoff. - Migration adds copilot_settings.seal_version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
||
| const USER = '11111111-1111-4111-8111-111111111111'; | ||
| const SESSION = 'sess-1'; | ||
| const ANTHROPIC = 'sk-ant-api03-abcdefghijklmnopqrstuv'; |
ThreatCrush Security Scan54 finding(s) HIGH/CRITICAL: 4 | MEDIUM: 29 | LOW: 21
…and 4 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
copilot_settings.anthropic_key / openai_key / elevenlabs_key (meeting copilot BYOK) were AES-256-GCM under the server env key
COPILOT_KEYS_SECRET: root on the box could open every user's keys. This moves them onto the seal v2 pieces from #165 (same key passphrase, sameuser_key_sealsrow, same unlock store), no second scheme.v2:), AAD binds user + field. 409 before a key passphrase exists; Settings > Copilot can set one (recovery key shown once).copilot:<user>:<session>(TTL default 8h) and dropped when the copilot stops, the meeting ends/is abandoned, on Lock (/api/keys/lock), or on restart. Opened keys are not cached past that.ownKeys.state.LEGACY_KEY_MIGRATION=offends it. Passphrase reset clears keys sealed to the old key.20261028230000_copilot_keys_sealed.sql: addscopilot_settings.seal_version. Prod had 0 copilot_settings rows.Tests: new
keys.test.ts(seal/unseal, AAD, per-meeting unlock TTL/lock/restart, separate from YouTube unlock, no env fallback, migration + cutoff, reset, no paid fallback while locked); full web suite 1225 pass, i18n catalogs (19 locales), desktop CLI tests, typecheck, web + desktop builds.🤖 Generated with Claude Code