T09 · Insecure Skill Coding Practices
- Location
store.py:30- Finding
Habit and Conversation Data Stored Without Explicitly Restrictive File Permissions
- Content
View full analysis
None: """保存用户数据,原子写入 + 文件锁""" tmp_file = self._data_file + ".tmp" try: data = user_data.to_dict() with open(tmp_file, "w", encoding="utf-8") as f: fcntl.flock(f.fileno(), fcntl.LOCK_EX) try: json.dump(data, f, ensure_ascii=False, indent=2) finally: fcntl.flock(f.fileno(), fcntl.LOCK_UN) # 原子替换 os.replace(tmp_file, self._data_file) ``` The persisted data includes user-controlled habit goals, check-in notes, coaching preferences, reminder information, and rationalization conversation history. For example, the conversation history is populated in `agent.py:112-117`: ```python if ai_message: rat.conversation.append(ConversationTurn(role="ai", content=ai_message)) if user_response: rat.conversation.append(ConversationTurn(role="user", content=user_response)) rat.round_count += 1 ``` ### Technical Analysis The data directory is created without an explicit mode, and the temporary JSON file is opened without setting or verifying restrictive permissions. Consequently: - Directory permissions are derived from the default creation mode and the process umask. - The temporary file is normally created from mode `0666`, modified only by the process umask. - `os.replace()` preserves the permissions of the temporary file when it becomes `habits.json`. - Corrupted and manually created backups use similarly inherited permissions. - All records are stored as unencrypted JSON. With a typical restrictive umask, practical exposure may be reduced. However, the code does not enforce that assumption. In environments wi ...[truncated 2004 chars]- Remediation
View remediation
