T09 · Insecure Skill Coding Practices
Warning
- Location
- agmsg_cli.py:103
- Finding
- Credential File Is Written Without Enforcing Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `agmsg_cli.py:103-127` **Vulnerability Type**: Insecure storage of sensitive credentials **Risk Level**: Medium ### Vulnerable Code ```python def _save_credentials_to_env(username: str, api_key: str) -> None: """Append or update AGMSG_USERNAME and AGMSG_API_KEY in .env file""" env_path = Path(".env") # Read existing .env content env_content = "" if env_path.exists(): with open(env_path, "r") as f: env_content = f.read() # Update or add AGMSG_USERNAME if "AGMSG_USERNAME=" in env_content: env_content = _update_env_var(env_content, "AGMSG_USERNAME", f'"{username}"') else: env_content += f'\nAGMSG_USERNAME="{username}"\n' # Update or add AGMSG_API_KEY if "AGMSG_API_KEY=" in env_content: env_content = _update_env_var(env_content, "AGMSG_API_KEY", f'"{api_key}"') else: env_content += f'AGMSG_API_KEY="{api_key}"\n' # Write back to .env with open(env_path, "w") as f: f.write(env_content) ``` ### Technical Analysis The account registration workflow stores the newly issued API key in `.env`, but the program does not create or update that file with an explicitly restrictive permission mode. A newly created file therefore inherits permissions determined by the process umask. In an environment with a permissive umask, the file may be readable by other local users or processes. This is especially sensitive because the documented `.env` configuration is also expected to contain `CLIENT_EVM_WALLET_SECRET`, which is the private key used to authorize x402 payments. Rewriting the complete existing file means both the API credential and any wallet private key already stored there remain protected only by the inherited file permissions. The implementation conflicts with the guidance in `SKILL.md`, which tells users to set `.env` permissions to `0600` but does not enforce this requirement progra ...[truncated 1209 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Create credential files atomically with mode `0600`, for example by using `os.open()` with `O_CREAT | O_WRONLY | O_TRUNC` and a mode of `0o600`. - Explicitly call `os.chmod(env_path, 0o600)` when updating an existing file. - Write through a securely created temporary file and atomically replace the destination to avoid partially written credential files. - Preserve restrictive ownership and permissions during replacement. - Before reading or writing, reject unexpected file types and verify that the file is owned by the current user. - Add an automated test that runs under a permissive umask and verifies that the final `.env` mode remains `0600`. - Keep the documented recommendation to use a dedicated, low-balance wallet as a defense-in-depth measure. ]]>
