T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/skill-list.py:20
- Finding
- Unsafe Pickle Deserialization Enables Arbitrary Code Execution## Vulnerability Details **File Location**: `scripts/skill-list.py`, lines 20–30 **Vulnerability Type**: Unsafe deserialization of a local cache file **Risk Level**: High ### Vulnerable Code ```python def load_cache() -> Dict[str, Any]: """加载缓存文件""" try: if not CACHE_FILE.exists(): return {"skill_names": [], "skills": [], "updated_at": ""} with open(CACHE_FILE, "rb") as f: cache = pickle.load(f) return cache except Exception as e: print(f"⚠️ 加载缓存失败: {e}") return {"skill_names": [], "skills": [], "updated_at": ""} ``` The cache is loaded automatically during normal execution: ```python # 1. 加载缓存 cache = load_cache() cache_skill_names = cache.get("skill_names", []) ``` ### Technical Analysis The application uses `pickle.load()` to deserialize `scripts/skills_cache.pickle`. Python Pickle is not a data-only serialization format: specially constructed objects can invoke arbitrary callables during deserialization through mechanisms such as `__reduce__`. Consequently, validation performed after `pickle.load()` cannot prevent exploitation because the payload executes while the file is being decoded. The surrounding exception handler also provides no protection against code execution that has already occurred. An attacker must first obtain the ability to create or modify the cache file. Plausible sources include another process or Skill running under the same account, an insecure deployment that permits modification of the Skill directory, or a tampered cache distributed alongside the project. The audited package did not contain a malicious cache file, so this finding identifies an exploitable coding flaw rather than confirmed malicious behavior. ### Attack Path 1. The attacker obtains write access to `scripts/skills_cache.pickle` or to the containing `scripts` directory. 2. The attacker creates a crafted Pickle object whose deserialization routine invokes an attacker-sele ...[truncated 1208 chars]
- Remediation
- ## Remediation Suggestions 1. **Replace Pickle with a data-only format.** Store the cache as JSON and decode it with `json.load()`. The existing fields consist of strings, booleans, lists, and dictionaries, all of which are directly representable in JSON. 2. **Do not migrate an existing Pickle cache by loading it.** Delete or ignore legacy `skills_cache.pickle` files and regenerate the cache by scanning the Skill directories. Loading an old cache for conversion would retain the vulnerability. 3. **Validate the decoded structure.** After JSON parsing, verify that: - The top-level value is a dictionary. - `skill_names` is a list containing only strings. - `skills` is a list of dictionaries with expected fields and types. - `updated_at` is a string. - Unexpected or oversized values are rejected. 4. **Protect cache integrity.** Store the cache in a user-private cache directory with restrictive permissions. Reject symlinked cache files and verify that the resolved path remains in the expected directory. 5. **Use atomic writes.** Write new cache data to a securely created temporary file in the same directory, set restrictive permissions, flush it, and atomically replace the destination. This reduces corruption and race-condition risks. 6. **Apply least privilege.** Run the Skill in a constrained environment without unnecessary access to credentials, sensitive directories, or privileged system interfaces.
