#7953: feat(security): encrypt credentials at rest with AES-256-GCM
commands
agents
stale
Cluster:
OpenClaw Plugin Enhancements
## Summary
Add **two-layer credential security** for OpenClaw: encryption at rest (AES-256-GCM) + OS keychain integration for the master key. Together, these layers protect credentials across multiple threat models.
## The Problem
OpenClaw stores API keys and OAuth tokens in plaintext JSON files. This creates risk from:
- Accidental git commits or backup leaks
- Casual file browsing (someone glancing at your screen)
- Log/error message exposure
- File-level access by other processes
## The Solution: Defense in Depth
### Layer 1: Encryption at Rest (AES-256-GCM)
All credential files (`auth-profiles.json`, etc.) are encrypted using AES-256-GCM with a per-installation master key. Plaintext files are automatically migrated on first access.
**Protects against:** backup leaks, git commits, log exposure, screenshots, casual file browsing.
### Layer 2: OS Keychain Integration
The master key is stored in the operating system's secure credential store rather than as a file on disk:
| Platform | Backend | Security Model |
|----------|---------|----------------|
| **macOS** | Keychain (`security` CLI) | Protected by user login + optional Touch ID |
| **Linux** | libsecret (`secret-tool`) | gnome-keyring / kwallet, session-locked |
| **Windows** | DPAPI (PowerShell) | Tied to Windows user login, hardware-backed |
| **Headless/Docker** | File fallback (`master.key`) | Graceful degradation |
**Protects against:** same-user file access, key co-location (addresses review feedback from @HenryLoenwind).
### Combined Protection Matrix
| Threat | Layer 1 (Encryption) | Layer 2 (Keychain) | Combined |
|--------|---------------------|-------------------|----------|
| Config in git/backup | ✅ Ciphertext only | — | ✅ |
| Casual file browsing | ✅ Not human-readable | — | ✅ |
| File-level attacker | ❌ Key on disk too | ✅ Key in OS vault | ✅ |
| Process with user access | ❌ | ⚠️ Session-dependent | ⚠️ |
| Root/admin access | ❌ | ❌ | ❌ (out of scope) |
## Migration
Fully automatic, zero user action required:
1. **Plaintext → Encrypted**: On first access, plaintext JSON files are encrypted in-place with atomic backup/recovery
2. **File key → Keychain**: If `master.key` exists on disk and OS keychain is available, the key is moved to the keychain and the file is deleted
3. **Graceful fallback**: If no keychain is available (headless servers, Docker, CI), file-based key storage continues working exactly as before
## Implementation Details
- **Zero new npm dependencies** — uses only Node.js built-ins (`crypto`, `child_process`, `fs`)
- **Encrypted envelope format** (v1): `{ version, algorithm, keyId, nonce, ciphertext, tag }`
- **Key tracking**: Short hash (`keyId`) in each envelope enables detection of key mismatches without exposing the key
- **Crash safety**: Atomic write with `.tmp`/`.bak` recovery for interrupted migrations
- **Logging**: One-time info messages for migration events and fallback decisions
## Files Changed
- `src/infra/crypto-store.ts` — Core encryption/decryption with keychain-first key management
- `src/infra/keychain.ts` — Cross-platform OS keychain abstraction (new)
- `src/infra/keychain.test.ts` — Keychain backend tests (new)
- `src/agents/auth-profiles/` — Updated to use encrypted storage throughout
## Complementary Approaches
This PR is complementary to Docker-based credential isolation (useful for server deployments). The encryption + keychain approach is designed for the common case: developers and users running OpenClaw on their own machines.
## Acknowledgments
Thanks to @HenryLoenwind for the review feedback that inspired the keychain integration. The observation that co-locating the key with encrypted data limits security was exactly right — and pushed us to build a more complete solution.
Most Similar PRs
#21554: feat(security): encrypt workspace files and config at rest
by joncode · 2026-02-20
81.4%
#21053: security(infra): OS keychain storage for device private keys
by richvincent · 2026-02-19
78.4%
#23574: security: P0 critical remediation — plugin sandbox, password hashin...
by lumeleopard001 · 2026-02-22
70.6%
#23110: feat(security): Credential Firewall — CredentialStore with domain p...
by ihsanmokhlisse · 2026-02-22
70.2%
#8821: Security: Holistic capability-based sandbox (replaces pattern-match...
by tonioloewald · 2026-02-04
69.1%
#19543: security: add encrypted localStorage wrapper using Web Crypto API
by Mozzzaic · 2026-02-17
69.0%
#23165: fix(security): detect plaintext credentials in security audit
by ihsanmokhlisse · 2026-02-22
68.4%
#20772: fix(security): OC-15 encrypt Nostr private keys to prevent plaintex...
by aether-ai-agent · 2026-02-19
68.3%
#16663: feat: GCP Secret Manager integration for external secrets management
by amor71 · 2026-02-15
68.0%
#10514: Security: harden AGENTS.md with gateway, prompt injection, and supp...
by catpilothq · 2026-02-06
67.5%