- The OpenAI API key is only ever present in the main process memory.
- It is never sent over IPC to the renderer.
- It is never hardcoded.
- It is never committed (
.envis gitignored; only.env.exampleexists). - It is never logged (logger redacts anything matching
sk-...).
- Dev:
process.env.OPENAI_API_KEY(from.env, loaded only in dev). - User-provided: pasted in Settings → encrypted at rest in SQLite.
Resolution order at call time: env var (if set) → decrypted stored key. If neither exists, OpenAI calls fail fast with a clear "No API key configured" error and the UI prompts the user to add one.
Primary backend: Electron safeStorage.
import { safeStorage } from 'electron';
// save:
const cipher = safeStorage.encryptString(plaintextKey); // Buffer
settings.set('openai_api_key_enc', cipher.toString('base64'));
settings.set('openai_api_key_present', '1');
// load (main only):
const enc = settings.get('openai_api_key_enc');
const key = enc ? safeStorage.decryptString(Buffer.from(enc, 'base64')) : null;safeStorageuses the OS keychain/DPAPI under the hood (macOS Keychain, Windows DPAPI, libsecret on Linux) to protect the encryption key.- Fallback: if
safeStorage.isEncryptionAvailable()is false (some Linux setups), warn the user and optionally fall back tokeytar, behind the sameApiKeyStoreinterface. Never silently store plaintext.
interface ApiKeyStore {
isPresent(): boolean; // safe to expose via IPC (boolean only)
set(plaintext: string): void; // encrypts + persists
clear(): void;
getDecrypted(): string | null; // MAIN ONLY — never crosses IPC
}- Only a boolean
apiKeyPresent(fromsettings:get). - A masked display like
sk-…last4is not provided by default (last-4 could be added later if desired; MVP exposes presence only).
settings:test-api-key does a cheap call (e.g. list models / tiny embedding) in
main and returns { ok, model } or { ok:false, error } — without revealing the
key.
- Central logger redacts
sk-[A-Za-z0-9_\-]+from all output. - No analytics/telemetry leaves the machine in MVP.
- A compromised renderer cannot exfiltrate the key (it never has it).
- Disk theft is mitigated by OS-backed encryption; not a substitute for full-disk encryption, which we recommend in docs.