T09 · Insecure Skill Coding Practices
- Location
reference/secrets-rpc.ts:34- Finding
Vault Stores Secrets as Plaintext and Does Not Enforce Permissions on Existing Files
- Content
View full analysis
): Promise { const filePath = getSecretsFilePath(); await fs.mkdir(path.dirname(filePath), { recursive: true }); await fs.writeFile(filePath, JSON.stringify(secrets, null, 2) + "\n", { mode: 0o600 }); } ``` The related UI inaccurately characterizes this storage as encrypted in `reference/apikeys-views.ts:49-51`: ```ts 🔒 Encrypted keys are stored in~/.openclaw/secrets.json(mode 0600). Config references point to the vault — the AI agent never sees your keys. ``` ### Technical Analysis The implementation serializes every API key and token directly into a JSON file without encryption. File mode `0600` is an operating-system access-control measure; it does not provide encryption at rest. Anyone who acquires readable access to the file, a filesystem snapshot, or an unencrypted backup can recover all credentials without additional key material. The `mode: 0o600` option passed to `fs.writeFile` controls permissions when a new file is created. It does not reliably correct an existing file that already has overly permissive permissions. Consequently, a vault created or replaced elsewhere with broader permissions may remain exposed after subsequent writes. The write is also performed directly against the destination file. A process interruption can leave the credential store partially written or corrupted. The local path is fixed rather than attacker-selected, but the shown implementation does not itself verify ownership, reject symbolic links, or use an atomic temporary-file replacement. The behavior is necessary insofar as the Skill must persist secrets, but plaintext storage and inaccurate encryption claims exceed an accept ...[truncated 1329 chars]- Remediation
View remediation
