T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/search.py:31
- Finding
- Unsafe Deserialization of Local Pickle Index Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/search.py:31-32`; `scripts/update.py:138-139` **Vulnerability Type**: Unsafe Python pickle deserialization **Risk Level**: High ### Vulnerable Code `scripts/search.py:31-32`: ```python with open(IMAGE_LIST_FILE, 'rb') as f: images = pickle.load(f) ``` `scripts/update.py:138-139`: ```python with open(IMAGE_LIST_FILE, 'rb') as f: existing_paths = pickle.load(f) ``` ### Technical Analysis The application loads `image_db/image_list.pkl` with Python's unrestricted `pickle.load()` function. Pickle is an executable serialization format: specially constructed objects can define reduction operations that invoke attacker-selected Python callables during deserialization. No signature, digest, ownership check, permission check, schema validation, or restricted unpickler is applied before the file is loaded. Consequently, the fact that the file is stored locally does not make deserialization safe. Any actor or process capable of modifying the project database directory can turn the index file into a code-execution vector. Both the search and incremental-update workflows reach the unsafe operation. The payload executes while the file is being loaded, before the path list is used for its intended purpose. ### Attack Path 1. An attacker obtains write access to the project directory or `image_db/image_list.pkl`. This could occur through another local account with applicable permissions, a compromised process, an unsafe archive extraction, or replacement of a shared project directory. 2. The attacker generates a malicious pickle whose deserialization reduction invokes an attacker-selected callable, such as a process-launch or file-operation function. 3. The attacker replaces the legitimate `image_list.pkl` with the malicious file. 4. The victim runs either `python scripts/search.py <query>` or `python scripts/update.py`. 5. `pickle.load()` processes the attacker-controlled object. 6. The embedded ...[truncated 715 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace pickle storage with a non-executable serialization format such as JSON: ```python import json with open(IMAGE_LIST_FILE, "r", encoding="utf-8") as f: images = json.load(f) if not isinstance(images, list) or not all(isinstance(path, str) for path in images): raise ValueError("Invalid image-list format") ``` 2. Update the writer to serialize the list using `json.dump()` and change the configured filename to `image_list.json`. 3. Validate the decoded structure, maximum entry count, individual path length, and expected value types before using the data. 4. Store index data in a user-private directory and apply permissions that prevent modification by other accounts. 5. If integrity against unauthorized modification is required, authenticate the index and path-list files with a signature or keyed MAC stored separately. 6. Do not attempt to make arbitrary pickle data safe through superficial type checks after loading; malicious behavior occurs during deserialization. 7. If a legacy migration is required, only convert pickle files generated in a trusted environment after checking file ownership and permissions, then delete the pickle file. ]]>
