T09 · Insecure Skill Coding Practices
Warning
- Location
- xhs_cli/cookies.py:58
- Finding
- Plaintext Session Cookies Are Created Before Restrictive Permissions Are Applied<![CDATA[ ## Vulnerability Details **File Location**: `xhs_cli/cookies.py:58-64` **Vulnerability Type**: Insecure plaintext credential storage and non-atomic file creation **Risk Level**: Medium ### Vulnerable Code ```python def save_cookies(cookies: dict[str, str]) -> None: """Save cookies to local storage with restricted permissions and TTL timestamp.""" cookie_path = get_cookie_path() payload = {**cookies, "saved_at": time.time()} cookie_path.write_text(json.dumps(payload, indent=2)) cookie_path.chmod(0o600) logger.debug("Saved cookies to %s", cookie_path) ``` ### Technical Analysis The application saves active Xiaohongshu browser cookies in plaintext. It creates or truncates `cookies.json` through `Path.write_text()` and only applies mode `0600` after the write completes. The file's initial permissions therefore depend on the process umask. With a permissive umask, another local user may be able to read the file between its creation and the subsequent `chmod()` call. If the process crashes, is terminated, or encounters an error before `chmod()` completes, the credential file may remain accessible with broader permissions. The operation is also non-atomic. A concurrent reader can potentially observe partially written data, and interruption can leave a truncated credential cache. Although the intended destination is `~/.xiaohongshu-cli/cookies.json`, the containing directory is created without explicitly enforcing mode `0700`. The cookies are authentication credentials capable of authorizing account reads and writes. Their local storage is part of the declared functionality, but creating the file before securing it is not necessary. ### Attack Path 1. A victim uses a multi-user system and has an authenticated Xiaohongshu browser session. 2. A local attacker monitors `~/.xiaohongshu-cli/` for creation or modification of `cookies.json`. 3. The victim runs `xhs login`, or an authenticated command automatically refreshes stale co ...[truncated 1306 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Create credential files with mode `0600` at the moment of creation rather than correcting permissions afterward. Use `os.open()` with explicit flags and permissions: ```python import os fd = os.open( cookie_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600, ) with os.fdopen(fd, "w", encoding="utf-8") as handle: json.dump(payload, handle, indent=2) ``` 2. Prefer an atomic replacement strategy: - Create a temporary file inside the same configuration directory. - Create it with mode `0600`. - Write and flush the complete payload. - Call `os.fsync()` where durability is required. - Atomically replace the destination with `os.replace()`. 3. Explicitly enforce mode `0700` on `~/.xiaohongshu-cli`, including when the directory already exists. 4. Reject symlinked credential paths and validate that the destination is a regular file owned by the current user before replacing it. 5. Where supported, store session credentials in an operating-system credential store instead of a plaintext JSON file. 6. Add tests verifying that both the configuration directory and credential file have restrictive permissions immediately upon creation. ]]>
