T09 · Insecure Skill Coding Practices
Error
- Location
- src/index.ts:38
- Finding
- Nostr Private Key Stored in a Plaintext Configuration File Without Restrictive Permissions## Vulnerability Details **File Location**: `src/index.ts:38-55`, with the sensitive value populated at `src/index.ts:129-134` **Vulnerability Type**: Plaintext storage of sensitive authentication material **Risk Level**: High ### Vulnerable Code ```ts const CONFIG_PATH = join(homedir(), ".agent-chat", "config.json"); function loadConfig(): Config { if (existsSync(CONFIG_PATH)) { return JSON.parse(readFileSync(CONFIG_PATH, "utf-8")); } throw new Error("Config not found. Run: agent-chat login <nsec>"); } function saveConfig(config: Config): void { const dir = join(homedir(), ".agent-chat"); import("fs").then(fs => { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2)); }); } ``` The configuration written by this function contains the supplied private key: ```ts const config: Config = { npub, nsec, relays: [], }; saveConfig(config); ``` ### Technical Analysis The `login` command places the complete Nostr private key (`nsec`, or a hexadecimal equivalent) in the configuration object. `saveConfig` serializes that object directly to `~/.agent-chat/config.json`. Neither the configuration directory nor the file is created with an explicit restrictive permission mode. Their effective permissions therefore depend on the process umask and any pre-existing filesystem objects. On a permissively configured multi-user system, another local account or process may be able to read the private key. The implementation also does not inspect or reject a pre-existing symbolic link at the configuration path. Consequently, local filesystem manipulation may redirect the write to another user-writable target when the CLI executes with greater privileges. ### Attack Path 1. A victim runs `agent-chat login <nsec>`. 2. The CLI serializes the supplied private key into `~/.agent-chat/config.j ...[truncated 1141 chars]
- Remediation
- ## Remediation Suggestions - Prefer an operating-system credential store or hardware-backed secret provider instead of a plaintext JSON file. - If file storage is unavoidable, create `~/.agent-chat` with mode `0700` and the configuration file with mode `0600`. - Open the destination using flags that prevent following symbolic links where supported, and verify that the destination is a regular file owned by the current user. - Write through a securely created temporary file in the same protected directory, set its permissions explicitly, and atomically rename it into place. - Validate and reject insecure permissions on pre-existing directories and files. - Separate public configuration such as relay URLs from private key material. - Document key rotation and revocation procedures for users whose configuration file may have been exposed. - Add automated tests that verify directory permissions, file permissions, symbolic-link handling, and failure behavior.
