Skip to content

credential_store: .encryption_key file persists on disk even when OS keyring succeeds #344

@jpoehnelt

Description

@jpoehnelt

Bug

get_or_create_key() in src/credential_store.rs unconditionally writes the encryption key to ~/.config/gws/.encryption_key on first run, before attempting to store it in the OS keyring. The file is never cleaned up after a successful keyring store.

This means on a macOS machine with a fully functional Keychain, the encryption key exists in two places:

  1. macOS Keychain (protected by login credentials / biometrics)
  2. ~/.config/gws/.encryption_key (protected only by file permissions 0600)

Impact

The file-based key makes credential files portable — copying the entire ~/.config/gws/ directory to another machine transfers both the encrypted credentials and the key needed to decrypt them, defeating the purpose of keyring-based key storage.

Root Cause

In credential_store.rs lines 64–120, the Err(keyring::Error::NoEntry) branch:

  1. Generates a random 256-bit key
  2. Writes it to .encryption_key (lines 102–115)
  3. Then does best-effort entry.set_password() (line 118)

The file write happens unconditionally regardless of whether the keyring store succeeds.

Proposed Fix

Only write .encryption_key as a fallback when the keyring is unavailable:

// Generate key
let mut key = [0u8; 32];
rand::thread_rng().fill_bytes(&mut key);
let b64_key = STANDARD.encode(key);

// Try keyring first
if entry.set_password(&b64_key).is_err() {
    // Keyring failed — persist to file as fallback
    write_key_file(&key_file, &b64_key);
} else {
    // Keyring succeeded — clean up any stale file
    let _ = std::fs::remove_file(&key_file);
}

Verification

ls -la ~/.config/gws/.encryption_key
# Should NOT exist on systems with a working keyring

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions