T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/_auth.py:47
- Finding
- Credential File Permissions Are Applied Non-Atomically and Permission Failures Are Suppressed## Vulnerability Details **File Location**: `scripts/_auth.py:47-59` **Vulnerability Type**: Insecure credential storage **Risk Level**: Medium ```python def write_config(data): CONFIG_DIR.mkdir(parents=True, exist_ok=True) try: os.chmod(CONFIG_DIR, 0o700) except Exception: pass with open(CONFIG_FILE, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) try: os.chmod(CONFIG_FILE, 0o600) except Exception: pass ``` ### Technical Analysis The configuration file contains `app_id`, `secret_key`, and a cached `access_token`. It is created using the process's default file-creation permissions and restricted to mode `0600` only after its contents have been written. This creates a non-atomic protection sequence in which the file's initial permissions depend on the active umask. The parent directory is similarly hardened after creation rather than created with a guaranteed restrictive mode. If the configured directory already exists, is shared, resides on a filesystem with unsuitable permission semantics, or a permission change fails, sensitive data may be exposed. Both `chmod` operations suppress every exception, so execution continues even when credential protection cannot be established. The implementation also does not verify the file's resulting owner, type, or permissions. ### Attack Path 1. A victim runs the Skill with a permissive umask or sets `CHANJING_CONFIG_DIR` to an existing shared or insufficiently protected directory. 2. `write_config()` opens and writes `credentials.json` using process-default creation permissions. 3. The subsequent `chmod()` fails, is ineffective on the selected filesystem, or cannot correct exposure that occurred during creation. 4. The exception is silently ignored, and the program continues as if credential storage were secure. 5. Another local user or process with directory access reads `credentials.json`. 6. The exposed `secret_key` or c ...[truncated 704 chars]
- Remediation
- ## Remediation Suggestions - Create the configuration directory with mode `0700` from the outset and verify its ownership and final permissions. - Write credentials to a securely created temporary file using exclusive creation and mode `0600`, then atomically replace the destination with `os.replace()`. - Flush and synchronize the temporary file before replacement where durability is required. - Reject symlinks and non-regular destination files where platform APIs permit. - Do not suppress permission errors. Fail closed with a clear error if secure storage cannot be established. - Verify the final file owner and permissions after writing. - Consider separating the long-lived secret key and cached access token from non-sensitive configuration and using an operating-system credential store where available. A hardened implementation should ensure that sensitive content is never present in a file with process-default or unverified permissions, even temporarily.
