T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/auth.py:60
- Finding
- API Key Stored Without Explicitly Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/auth.py:60-73` **Vulnerability Type**: Plaintext credential file with inherited permissions **Risk Level**: Medium ### Vulnerable Code ```python UPKUAJING_DIR.mkdir(parents=True, exist_ok=True) with open(env_file, 'w', encoding='utf-8') as f: f.write(f"{API_KEY_ENV}={api_key}\n") ``` ### Technical Analysis The Skill stores a bearer API key in `~/.upkuajing/.env`. Reading this dedicated credential file is necessary for the declared API functionality and does not, by itself, exceed minimum privilege. However, the file and its parent directory are created without explicit restrictive permissions. The resulting permissions depend on the user's process umask and existing directory permissions. In an environment with a permissive umask or a pre-existing broadly accessible directory, another local account or process may be able to read the API key. The implementation also does not defend against the credential path being a symbolic link. If an attacker can control the `~/.upkuajing` directory or `.env` entry, opening the path with truncation could overwrite a file accessible to the victim account. ### Attack Path 1. A victim runs `python scripts/auth.py --new_key`. 2. The Skill requests a new API key from the UpKuaJing service. 3. The returned bearer key is written to `~/.upkuajing/.env` using permissions inherited from the runtime environment. 4. A local attacker with access allowed by those permissions reads the file. 5. The attacker uses the bearer key against the UpKuaJing API. 6. The attacker may consume the victim's API balance, retrieve associated account information, or create a payment-order URL. A symlink-based path is also possible if an attacker already has sufficient local access to manipulate the credential directory before the command runs. ### Impact Assessment Successful exploitation discloses the UpKuaJing bearer credential. The attacker obtains the same API privileges as ...[truncated 242 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Create the credential directory with owner-only permissions: ```python UPKUAJING_DIR.mkdir(mode=0o700, parents=True, exist_ok=True) os.chmod(UPKUAJING_DIR, 0o700) ``` 2. Create the credential file atomically with mode `0600`: ```python flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(env_file, flags, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: f.write(f"{API_KEY_ENV}={api_key}\n") ``` 3. Reject symbolic links and verify that the resolved file remains inside the expected directory. 4. Verify and repair permissions on an existing credential file before reading it. 5. Prefer an operating-system credential store or secret manager where available. 6. Avoid displaying any portion of an existing key in error messages, even though the current implementation only displays a prefix. ]]>
