T09 · Insecure Skill Coding Practices
- Location
scripts/shared/storage/keys.js:13- Finding
Unencrypted Private Keys Are Stored Without Explicit Restrictive File Permissions
- Content
View full analysis
entry.alias === args.alias); if (index >= 0) { keys[index].privateKeyHex = args.key; } else { keys.push({ alias: args.alias, privateKeyHex: args.key }); } await this.writeFile(keys); } ``` `scripts/shared/storage/base.js:24-30`: ```js async writeFile(data) { await this.ensureDirectory(); const json = JSON.stringify(data, null, 2); const tempPath = `${this.filePath}.tmp`; await fs.writeFile(tempPath, json, "utf-8"); await fs.rename(tempPath, this.filePath); } ``` ### Technical Analysis The key store serializes private keys directly into JSON and writes them to `$HOME/.openclaw/billions/kms.json`. The temporary file and final file are not created with an explicit `0600` mode, while the containing directory is not explicitly created with a `0700` mode. Protection therefore depends on the process umask and any permissions already present on the directory or files. The temporary file contains the same plaintext private keys as the final file. If a write or rename fails, that temporary file may remain on disk. No operating-system keychain, encrypted keystore, hardware-backed key store, or application-level encryption protects the key material. Although private-key storage is necessary for the declared signing functionality, plaintext storage without enforced access controls exceeds the minimum safe privilege model for long-lived identity credentials. ### Attack Path 1. A user creates or imports an identity through the Skill. 2. The Skill writes the identity private key into `kms.json.tmp` and renames it to `kms.json`. ...[truncated 1031 chars]- Remediation
View remediation
