-
-
Notifications
You must be signed in to change notification settings - Fork 322
safeStorage claimed in SECURITY.md but not implemented — API keys stored in plaintext #532
Description
Summary
SECURITY.md states:
"Credential storage -- Sensitive credentials are stored using Electron's
safeStorageAPI where available."
However, safeStorage is not used anywhere in the codebase. A code search for safeStorage returns only the SECURITY.md file itself — zero matches in source code.
Current behavior
API keys (Groq, OpenAI, Anthropic, etc.) are stored in two plaintext locations:
- Electron
localStorage— viasettingsStore.ts(e.g.,localStorage.setItem("groqApiKey", key)) — which is an unencrypted SQLite file on disk .envfile — viaEnvironmentManagerinsrc/helpers/environment.js, written to the ElectronuserDatadirectory
Both are readable by any process running as the current OS user.
Additionally, debug logging in audioManager.js logs the first 8 characters of API keys (keyPreview), which for keys with short prefixes (e.g., Groq's gsk_) leaks part of the actual secret.
Expected behavior
Use Electron's safeStorage API as documented, which encrypts credentials using the platform's native keychain (macOS Keychain, Windows DPAPI, libsecret on Linux):
// Store
const encrypted = safeStorage.encryptString(apiKey);
fs.writeFileSync(keyPath, encrypted);
// Retrieve
const encrypted = fs.readFileSync(keyPath);
const apiKey = safeStorage.decryptString(encrypted);Impact
Users providing their own API keys (BYOK) trust that credential storage follows the documented security model. The current implementation doesn't match the documented claims.
Environment
- Tested against: current
mainbranch (v1.6.6) - Platform: macOS