T09 · Insecure Skill Coding Practices
- Location
- SKILL.md:22
- Finding
- Bearer API Key Stored Without Required File-System Protections<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 22-25; repeated guidance at line 41 and in `references/api.md`, line 14 **Vulnerability Type**: Insecure plaintext credential storage **Risk Level**: Medium ### Vulnerable Code Snippet ```markdown Store at `~/.rpc/credentials.json`: ```json {"agentId": "agent_xxx", "apiKey": "rpc_xxx", "eventId": "evt_global"} ``` ``` The related registration workflow states: ```markdown Save the returned `agentId`, `apiKey`, and `eventId` to `~/.rpc/credentials.json`. ``` ### Technical Analysis The Skill requires a bearer API key to be persisted in `~/.rpc/credentials.json`, but it does not require the containing directory or file to be created with restrictive permissions. It also does not require ownership validation, symlink protection, or atomic file replacement. The API key is an authentication secret. Possession allows requests to authenticated game endpoints without additional identity verification. The actual exposure depends on the host's default umask and the implementation used to write the file. Under permissive settings, another local account may be able to read it. Other processes operating in the same user context can also access an ordinary plaintext file. A predictable credential path creates an additional risk if an attacker can prepare `~/.rpc/credentials.json` as a symbolic link before registration. An unsafe writer could overwrite another file writable by the agent account or save the secret at an attacker-controlled destination. Local persistence of a game-specific credential is necessary for the declared functionality, but unrestricted plaintext storage is not the minimum safe privilege required. ### Attack Path 1. A user directs the Skill to register for the game. 2. The remote service returns an `agentId`, `apiKey`, and `eventId`. 3. The Skill writes these values to the predictable path `~/.rpc/credentials.json`. 4. The file is created using unspecified default permissi ...[truncated 1096 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Prefer an operating-system credential manager or secret service instead of a plaintext JSON file. - If file storage is necessary: - Create `~/.rpc` with permission mode `0700`. - Create the credential file with mode `0600`. - Set restrictive permissions explicitly rather than relying on the process umask. - Verify that both the directory and file are owned by the current user. - Reject symbolic links and non-regular files. - Write to a securely created temporary file in the same directory, set its permissions, flush it, and atomically rename it. - Never print the API key in logs, user-facing status messages, command traces, or error reports. - Validate the credential document's schema before use and reject unexpected fields. - Document secure deletion and key-rotation procedures for compromised credentials. - Scope API keys to only the endpoints needed for gameplay where supported. ]]>
