T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/colony-client.py:8
- Finding
- Unsafe bearer-token cache in a predictable shared directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/colony-client.py`, lines 8–10 and 37–42 **Vulnerability Type**: Predictable sensitive temporary file, symlink following, and non-atomic permission hardening **Risk Level**: High ### Vulnerable Code ```python WORKSPACE = Path(__file__).parent.parent.parent.parent CACHE_FILE = WORKSPACE / ".colony-token-cache.json" SECRETS_FILE = WORKSPACE / ".secrets-cache.json" ``` ```python CACHE_FILE.write_text(json.dumps({ "token": token, "expires_at": time.time() + TOKEN_TTL, "created_at": time.time() })) os.chmod(CACHE_FILE, 0o600) ``` ### Technical Analysis The bearer token is written to a fixed, predictable path using `Path.write_text()`. Given the audited installation path, the four-level parent traversal resolves `WORKSPACE` to `/tmp`, making the resulting cache path `/tmp/.colony-token-cache.json`. The code does not: - Reject symbolic links. - Verify that the existing file is owned by the current user. - Create the file with exclusive semantics. - Set mode `0600` at file-creation time. - Use an atomic, user-private credential store. `Path.write_text()` follows an existing symbolic link. In addition, `chmod()` is invoked only after sensitive data has already been written. If the path is attacker-controlled, the token may therefore be redirected or exposed before permission hardening occurs. A failed `chmod()` does not undo the preceding write. The cached token remains valid for up to 23 hours and is used as a bearer credential for all authenticated Colony API operations. ### Attack Path A practical attack requires another local user or process able to create entries in the shared workspace: 1. The attacker determines that the Skill resolves its cache path to `/tmp/.colony-token-cache.json`. 2. Before the victim authenticates, the attacker creates that path as a symbolic link to a file that the victim can write and the attacker can subsequently read, or otherwise prepares an attacker-c ...[truncated 1499 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Store the token under a user-private state directory, such as: - `$XDG_STATE_HOME/colony-engagement/token.json`, or - `~/.local/state/colony-engagement/token.json`. 2. Create the parent directory with mode `0700` and verify that it is owned by the current user. 3. Reject existing symbolic links and files with unexpected ownership or permissions. 4. Create temporary and destination files with restrictive permissions from the outset, using flags such as `O_CREAT | O_EXCL | O_NOFOLLOW` and mode `0600`. 5. Write the data to a securely created temporary file in the same private directory, flush it, and atomically replace the cache file. 6. Validate cached JSON and required fields before use. 7. Delete expired tokens promptly rather than leaving them indefinitely on disk. 8. Consider using an operating-system credential store instead of a plaintext JSON token cache. 9. Do not print any token prefix during authentication, because even partial token disclosure is unnecessary. ]]>
