- Location
- integrations/memory_manager.py:42
- Finding
- Unsanitized User Identifier Enables Filesystem Path Traversal<![CDATA[
## Vulnerability Details
**File Location**: `integrations/memory_manager.py:42-77`; deletion is also affected at `integrations/memory_manager.py:221-226`
**Vulnerability Type**: Path traversal causing unauthorized file read, write, and deletion
**Risk Level**: High
### Vulnerable Code
```python
def load_history(self, user_id: str) -> list:
"""加载对话历史"""
path = os.path.join(self.storage_dir, f"{user_id}_history.json")
if os.path.exists(path):
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
return []
def save_history(self, user_id: str, history: list):
"""保存对话历史(只保留最近 N 轮)"""
max_msgs = SHORT_TERM_ROUNDS * 2
if len(history) > max_msgs:
history = history[-max_msgs:]
path = os.path.join(self.storage_dir, f"{user_id}_history.json")
with open(path, 'w', encoding='utf-8') as f:
json.dump(history, f, ensure_ascii=False, indent=2)
def add_message(self, user_id: str, role: str, content: str) -> list:
"""添加一条消息到历史"""
history = self.load_history(user_id)
history.append({"role": role, "content": content})
self.save_history(user_id, history)
return history
# ========== 长期记忆(摘要压缩)==========
def load_memory(self, user_id: str) -> str:
"""加载长期记忆"""
path = os.path.join(self.storage_dir, f"{user_id}_memory.md")
if os.path.exists(path):
with open(path, 'r', encoding='utf-8') as f:
return f.read()
return ""
def save_memory(self, user_id: str, content: str):
"""保存长期记忆"""
path = os.path.join(self.storage_dir, f"{user_id}_memory.md")
with open(path, 'w', encoding='utf-8') as f:
f.write(content)
```
The same pattern is used for deletion:
```python
def clear(self, user_id: str):
"""清除用户所有记忆"""
for suffix in ['_history.json', '_memory.md', '_stats.json']:
...[truncated 1822 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
- Do not use raw user identifiers as filenames.
- Convert identifiers to a fixed safe representation, such as a SHA-256 digest or a server-generated UUID.
- If readable identifiers are required, enforce a strict allowlist such as `^[A-Za-z0-9_-]{1,64}$`.
- Resolve both the storage root and candidate path with `pathlib.Path.resolve()`, then verify that the candidate is a descendant of the storage root.
- Reject absolute paths, separators, `.` and `..` components, NUL characters, and platform-specific path syntax.
- Reject symlink targets or open files using platform controls that prevent symlink following where available.
- Create storage files with restrictive permissions.
- Add tests covering `../`, absolute paths, encoded separators, Windows drive paths, and symlink attacks.
]]>