Summary
Supply chain attacks (e.g. LiteLLM) scrape SSH keys and secrets from compromised machines. Unpassphrased SSH private keys are immediately usable by attackers. devc-remote.sh should enforce a configurable security policy on SSH keys before connecting, and the team's dev environment should provide FIDO2-capable SSH by default.
Problem
Unpassphrased SSH private keys are equivalent to plaintext passwords on disk. Any process with file read access (malicious dependency, compromised tool, supply chain attack) can exfiltrate and immediately use them.
Detection is trivial: ssh-keygen -y -P "" -f <key> succeeds if a key has no passphrase.
Cross-Platform SSH Security
What stops scraped secrets from being usable
| Protection |
Scrape the file |
Brute-forceable? |
SSH key + passphrase (ed25519, bcrypt KDF -a 100) |
Encrypted blob |
Infeasible with strong passphrase |
| SSH key on YubiKey / FIDO2 |
Nothing to scrape — key never leaves hardware |
N/A |
| macOS Keychain (Secure Enclave) |
Encrypted blob, needs biometric |
Tied to hardware |
| age-encrypted files (X25519) |
Encrypted blob |
Infeasible — Curve25519 |
| Plain env var / unencrypted key |
Game over |
N/A |
Platform authenticator reality
| Platform |
FIDO2 SSH (ed25519-sk) |
Auth gesture |
External device? |
| macOS |
YubiKey only (Secure Enclave can't act as FIDO2 for SSH) |
Touch the key |
Yes |
| macOS |
Passphrased key + ssh-agent + UseKeychain |
Touch ID to unlock agent |
No |
| Linux |
YubiKey |
Touch the key |
Yes |
| Linux |
tpm2-fido (emulates FIDO2 via TPM2 chip) |
PIN / fingerprint (PAM) |
No |
Pragmatic recommendation (no external hardware needed)
Passphrased ed25519 keys + ssh-agent + ControlMaster = one Touch ID / password prompt per session, keys encrypted at rest, nothing usable if scraped.
Nix Home Manager Config (implemented)
Added to dotfiles/home/common.nix:
home.packages = [ pkgs.openssh ]; # FIDO2-capable (libfido2 built in)
programs.ssh = {
enable = true;
addKeysToAgent = "yes";
controlMaster = "auto";
controlPath = "~/.ssh/cm-%r@%h:%p";
controlPersist = "10m";
extraOptionOverrides.SecurityKeyProvider = "internal";
};
macOS-specific in darwin.nix:
programs.ssh.extraOptionOverrides.UseKeychain = "yes";
This gives:
- nixpkgs openssh with
libfido2 linked (withFIDO = true by default)
- ControlMaster — one auth per host, reused for 10 min (solves multi-touch problem for
devc-remote.sh)
- AddKeysToAgent — passphrase cached in agent after first use
- UseKeychain (macOS) — Touch ID unlocks passphrased keys
- SecurityKeyProvider = internal — builtin libfido2 for
ed25519-sk keys
Proposed: Client-Side Enforcement in devc-remote.sh
check_ssh_key_security() pre-flight
check_ssh_key_security() {
local host="$1"
local key
key=$(ssh -G "$host" | awk '/^identityfile / {print $2}' | head -1)
key="${key/#\~/$HOME}"
# FIDO2 hardware key — always OK
if [[ -f "${key}.pub" ]] && grep -qE 'sk-ssh-ed25519|sk-ecdsa' "${key}.pub"; then
return 0
fi
# Check for passphrase
if ssh-keygen -y -P "" -f "$key" &>/dev/null 2>&1; then
log_error "SSH key $key has NO passphrase — refusing to connect."
log_error "Fix: ssh-keygen -p -f $key -a 100"
return 1
fi
}
Configurable policy levels
In ~/.config/devc-remote/config.yaml:
ssh_key_policy: strict # warn | strict | fido2-only
| Policy |
Unpassphrased |
Passphrased |
FIDO2/YubiKey |
warn |
Warning |
OK |
OK |
strict (default) |
Blocked |
OK |
OK |
fido2-only |
Blocked |
Blocked |
OK |
Remediation guidance
✗ SSH key ~/.ssh/id_ed25519_ksb has NO passphrase — refusing to connect.
To add a passphrase to your existing key (key itself doesn't change):
ssh-keygen -p -f ~/.ssh/id_ed25519_ksb -a 100
To generate a FIDO2 hardware key (YubiKey):
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_ksb
To use ssh-agent with confirmation (Touch ID per use):
ssh-add -c ~/.ssh/id_ed25519_ksb # Linux
ssh-add --apple-use-keychain -c ~/.ssh/id_ed25519_ksb # macOS
To downgrade policy (not recommended):
Set ssh_key_policy: warn in ~/.config/devc-remote/config.yaml
Server-side enforcement (optional, documented)
For hosts where hardware keys should be mandatory:
# /etc/ssh/sshd_config.d/fido2-only.conf
PubkeyAcceptedAlgorithms sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com
Acceptance Criteria
Related
Summary
Supply chain attacks (e.g. LiteLLM) scrape SSH keys and secrets from compromised machines. Unpassphrased SSH private keys are immediately usable by attackers.
devc-remote.shshould enforce a configurable security policy on SSH keys before connecting, and the team's dev environment should provide FIDO2-capable SSH by default.Problem
Unpassphrased SSH private keys are equivalent to plaintext passwords on disk. Any process with file read access (malicious dependency, compromised tool, supply chain attack) can exfiltrate and immediately use them.
Detection is trivial:
ssh-keygen -y -P "" -f <key>succeeds if a key has no passphrase.Cross-Platform SSH Security
What stops scraped secrets from being usable
-a 100)Platform authenticator reality
ed25519-sk)ssh-agent+UseKeychaintpm2-fido(emulates FIDO2 via TPM2 chip)Pragmatic recommendation (no external hardware needed)
Passphrased ed25519 keys + ssh-agent + ControlMaster = one Touch ID / password prompt per session, keys encrypted at rest, nothing usable if scraped.
Nix Home Manager Config (implemented)
Added to
dotfiles/home/common.nix:macOS-specific in
darwin.nix:This gives:
libfido2linked (withFIDO = trueby default)devc-remote.sh)ed25519-skkeysProposed: Client-Side Enforcement in
devc-remote.shcheck_ssh_key_security()pre-flightConfigurable policy levels
In
~/.config/devc-remote/config.yaml:warnstrict(default)fido2-onlyRemediation guidance
Server-side enforcement (optional, documented)
For hosts where hardware keys should be mandatory:
Acceptance Criteria
openssh(FIDO2-capable) todotfiles/home/common.nixprograms.sshconfig with ControlMaster, AddKeysToAgent, SecurityKeyProviderUseKeychainindarwin.nixcheck_ssh_key_security()pre-flight indevc-remote.shssh -G <host>warn/strict/fido2-onlyssh-add -cand macOS Touch ID agent integrationPubkeyAcceptedAlgorithmsfor FIDO2-only hoststpm2-fidofor Linux users without YubiKeyRelated