T09 · Insecure Skill Coding Practices
- Location
scripts/pangolin.py:135- Finding
Permanent API Token Is Written Using Unsafe Non-Atomic File Handling
- Content
View full analysis
Vulnerability Details
File Location:
scripts/pangolin.py, lines 135-153
Vulnerability Type: Insecure secret storage and symbolic-link file overwrite
Risk Level: MediumVulnerable Code
python def save_cached_api_key(api_key): """Save API key to cache file.""" API_KEY_CACHE_PATH.write_text(api_key) try: API_KEY_CACHE_PATH.chmod(0o600) except OSError: pass # Windows: restrict file access to current user if sys.platform == "win32": try: import subprocess subprocess.run( ["icacls", str(API_KEY_CACHE_PATH), "/inheritance:r", "/grant:r", f"{os.environ.get('USERNAME', '')}:F"], capture_output=True, check=False, ) except Exception: passTechnical Analysis
Path.write_text()creates or truncates the cache file before restrictive permissions are applied. The initial permissions therefore depend on the process umask. On systems with a permissive umask, the permanent API token may briefly or persistently be readable by other local users.Permission-hardening failures are silently ignored. Consequently, the function can report successful authentication even when the token remains stored with insecure permissions.
The operation also follows an existing symbolic link. It does not verify that
~/.pangolin_api_keyis a regular file owned by the current user. A local process capable of manipulating this path can redirect the write to another user-writable file or monitor the destination during creation. The token is documented as permanent, increasing the consequences of disclosure.The Windows hardening command also uses
check=Falseand suppresses all exceptions, so access-control failures do not prevent continued use of the insecure cache.Attack Path
- A local malicious process running in a context that can manipulate ...[truncated 1501 chars]
- Remediation
View remediation
Remediation Suggestions
- Prefer an operating-system credential store such as Keychain, Credential Manager, or Secret Service instead of a plaintext file.
- Make persistent caching opt-in and provide a command to remove or revoke the cached token.
- On POSIX systems, create the file securely with
os.open()usingO_WRONLY | O_CREAT | O_EXCL, mode0o600, andO_NOFOLLOWwhere supported. - For updates, write to a securely created temporary file in the same directory, flush it with
fsync(), and atomically replace the validated destination. - Use
lstat()to reject symbolic links and verify that an existing cache is a regular file owned by the current user. - Set restrictive permissions at creation time rather than writing first and calling
chmod()afterward. - Fail closed if ownership or access-control hardening cannot be verified.
- On Windows, check the
icaclsreturn code and stop caching if the ACL cannot be restricted. - Avoid printing any portion of the token unless diagnostic preview behavior is explicitly requested.
