T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/teaming-manager.py:18
- Finding
- Plaintext Storage of Raw Personal Contact Information<![CDATA[ ## Vulnerability Details **File Location**: `scripts/teaming-manager.py`, lines 18, 36–39, and 103–104 **Vulnerability Type**: Plaintext sensitive-data storage with insufficient file-permission enforcement **Risk Level**: High ### Vulnerable Code ```python DATA_FILE = Path.home() / ".openclaw" / "workspace" / "memory" / "teaming-requests.json" ``` ```python def save_data(data: dict): """保存数据""" data["lastUpdated"] = datetime.now().isoformat() with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` ```python "contact": contact, "contactMasked": mask_contact(contact), ``` ### Technical Analysis The teaming feature stores both the masked contact value and the original contact value in a predictable JSON file under the user's home directory. The original value may contain a phone number, email address, QQ identifier, WeChat identifier, or another personal contact credential. Although the application generates a masked representation, retaining the raw value defeats data minimization. The implementation also opens the file without explicitly enforcing restrictive permissions. Consequently, the resulting access permissions depend on the process environment and its `umask`. The raw contact value is not necessary for the documented matching calculation. Matching uses competition names, skills, and availability, while output is explicitly supposed to use the masked value. Therefore, retaining raw contact information exceeds the minimum data privileges needed for the declared functionality. ### Attack Path 1. A user submits a teaming request containing a phone number, email address, QQ ID, or WeChat ID. 2. `add_request()` inserts both `contact` and `contactMasked` into the request object. 3. `save_data()` serializes the complete object to the predictable path `~/.openclaw/workspace/memory/teaming-requests.json`. 4. A local user, process, plugin, backup service, or other ...[truncated 690 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not persist the original `contact` value unless there is a documented functional requirement for it. Store only `contactMasked` where possible. 2. If later disclosure of the original contact is necessary, encrypt it using authenticated encryption and keep encryption keys outside the data file. 3. Create the storage file with owner-only permissions such as `0600`, and ensure the parent directory is accessible only by the owning account. 4. Write updates atomically through a securely created temporary file, apply restrictive permissions, and then replace the destination. 5. Introduce a retention policy that removes expired, closed, or abandoned requests and their associated contact data. 6. Validate that backups, diagnostic output, and logs cannot capture the raw contact value. 7. Document user consent, storage duration, deletion controls, and the purpose for which contact information is retained. ]]>
