mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
fix(security): prevent path traversal in memory content API
This commit is contained in:
@@ -134,6 +134,8 @@ class MemoryService:
|
|||||||
else:
|
else:
|
||||||
return {"action": action, "code": 400, "message": f"unknown action: {action}", "payload": None}
|
return {"action": action, "code": 400, "message": f"unknown action: {action}", "payload": None}
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
return {"action": action, "code": 403, "message": "invalid filename", "payload": None}
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
return {"action": action, "code": 404, "message": str(e), "payload": None}
|
return {"action": action, "code": 404, "message": str(e), "payload": None}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -145,14 +147,26 @@ class MemoryService:
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
def _resolve_path(self, filename: str) -> str:
|
def _resolve_path(self, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
Resolve a filename to its absolute path.
|
Safely resolve a filename to its absolute path within the allowed directory.
|
||||||
|
|
||||||
- ``MEMORY.md`` → ``{workspace_root}/MEMORY.md``
|
- ``MEMORY.md`` → ``{workspace_root}/MEMORY.md``
|
||||||
- ``2026-02-20.md`` → ``{workspace_root}/memory/2026-02-20.md``
|
- ``2026-02-20.md`` → ``{workspace_root}/memory/2026-02-20.md``
|
||||||
|
|
||||||
|
Raises ValueError if the resolved path escapes the allowed directory
|
||||||
|
(path traversal protection).
|
||||||
"""
|
"""
|
||||||
if filename == "MEMORY.md":
|
if filename == "MEMORY.md":
|
||||||
return os.path.join(self.workspace_root, filename)
|
base_dir = self.workspace_root
|
||||||
return os.path.join(self.memory_dir, filename)
|
else:
|
||||||
|
base_dir = self.memory_dir
|
||||||
|
|
||||||
|
resolved = os.path.realpath(os.path.join(base_dir, filename))
|
||||||
|
allowed = os.path.realpath(base_dir)
|
||||||
|
|
||||||
|
if resolved != allowed and not resolved.startswith(allowed + os.sep):
|
||||||
|
raise ValueError(f"Invalid filename: path traversal detected")
|
||||||
|
|
||||||
|
return resolved
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _file_info(path: str, filename: str, file_type: str) -> dict:
|
def _file_info(path: str, filename: str, file_type: str) -> dict:
|
||||||
|
|||||||
@@ -1365,6 +1365,8 @@ class MemoryContentHandler:
|
|||||||
service = MemoryService(workspace_root)
|
service = MemoryService(workspace_root)
|
||||||
result = service.get_content(params.filename)
|
result = service.get_content(params.filename)
|
||||||
return json.dumps({"status": "success", **result}, ensure_ascii=False)
|
return json.dumps({"status": "success", **result}, ensure_ascii=False)
|
||||||
|
except ValueError:
|
||||||
|
return json.dumps({"status": "error", "message": "invalid filename"})
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return json.dumps({"status": "error", "message": "file not found"})
|
return json.dumps({"status": "error", "message": "file not found"})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -68,12 +68,15 @@ Thanks [@WecomTeam](https://github.com/WecomTeam)
|
|||||||
## 🐛 其他优化与修复
|
## 🐛 其他优化与修复
|
||||||
|
|
||||||
- **DeepSeek 独立模块**:新增独立的 DeepSeek Bot 模块,支持 `deepseek_api_key` 专属配置,无需再通过 OpenAI 兼容方式接入([#2719](https://github.com/zhayujie/chatgpt-on-wechat/pull/2719))。Thanks [@6vision](https://github.com/6vision)
|
- **DeepSeek 独立模块**:新增独立的 DeepSeek Bot 模块,支持 `deepseek_api_key` 专属配置,无需再通过 OpenAI 兼容方式接入([#2719](https://github.com/zhayujie/chatgpt-on-wechat/pull/2719))。Thanks [@6vision](https://github.com/6vision)
|
||||||
- **Web 控制台斜杠菜单**:输入框输入 `/` 弹出指令快捷菜单([#2731](https://github.com/zhayujie/chatgpt-on-wechat/pull/2731))。Thanks [@zkjqd](https://github.com/zkjqd)
|
- **Web 控制台优化**:新增斜杠指令菜单和输入历史回溯,新增模型选项,优化移动端适配([#2731](https://github.com/zhayujie/chatgpt-on-wechat/pull/2731))。Thanks [@zkjqd](https://github.com/zkjqd)
|
||||||
- **上下文丢失**:修复上下文裁剪后丢失的问题 ([393f0c0](https://github.com/zhayujie/chatgpt-on-wechat/commit/393f0c0))
|
- **上下文丢失**:修复上下文裁剪后丢失的问题 ([393f0c0](https://github.com/zhayujie/chatgpt-on-wechat/commit/393f0c0))
|
||||||
- **系统提示词**:修复系统提示词未在每轮重建的问题 ([13f5fde](https://github.com/zhayujie/chatgpt-on-wechat/commit/13f5fde))
|
- **系统提示词**:修复系统提示词未在每轮重建的问题 ([13f5fde](https://github.com/zhayujie/chatgpt-on-wechat/commit/13f5fde))
|
||||||
|
- **Agent 响应**:去除 Agent 响应首尾空白字符 ([f890318](https://github.com/zhayujie/chatgpt-on-wechat/commit/f890318))
|
||||||
|
- **视觉压缩**:优化视觉图片压缩策略 ([22b8ca0](https://github.com/zhayujie/chatgpt-on-wechat/commit/22b8ca0))
|
||||||
- **Gemini 模型**:修复 GoogleGeminiBot 缺少 model 属性的问题([#2716](https://github.com/zhayujie/chatgpt-on-wechat/pull/2716))。Thanks [@cowagent](https://github.com/cowagent)
|
- **Gemini 模型**:修复 GoogleGeminiBot 缺少 model 属性的问题([#2716](https://github.com/zhayujie/chatgpt-on-wechat/pull/2716))。Thanks [@cowagent](https://github.com/cowagent)
|
||||||
- **微信通道**:修复文件发送失败、文件名丢失等问题 ([6d9b7ba](https://github.com/zhayujie/chatgpt-on-wechat/commit/6d9b7ba)、[45faa9c](https://github.com/zhayujie/chatgpt-on-wechat/commit/45faa9c))
|
- **微信通道**:修复文件发送失败、文件名丢失等问题 ([6d9b7ba](https://github.com/zhayujie/chatgpt-on-wechat/commit/6d9b7ba)、[baf66a1](https://github.com/zhayujie/chatgpt-on-wechat/commit/baf66a1)、[45faa9c](https://github.com/zhayujie/chatgpt-on-wechat/commit/45faa9c))
|
||||||
- **Docker 优化**:修复卷权限问题,精简镜像体积 ([3eb8348](https://github.com/zhayujie/chatgpt-on-wechat/commit/3eb8348)、[4470d4c](https://github.com/zhayujie/chatgpt-on-wechat/commit/4470d4c))
|
- **Docker 优化**:修复卷权限问题,精简镜像体积 ([3eb8348](https://github.com/zhayujie/chatgpt-on-wechat/commit/3eb8348)、[4470d4c](https://github.com/zhayujie/chatgpt-on-wechat/commit/4470d4c))
|
||||||
|
- **README 排版**:优化中英文排版空格([#2723](https://github.com/zhayujie/chatgpt-on-wechat/pull/2723))。Thanks [@Xiaozhou345](https://github.com/Xiaozhou345)
|
||||||
|
|
||||||
## 📦 升级方式
|
## 📦 升级方式
|
||||||
|
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ class CowCliPlugin(Plugin):
|
|||||||
page = min(page, total_pages)
|
page = min(page, total_pages)
|
||||||
installed = set(load_skills_config().keys())
|
installed = set(load_skills_config().keys())
|
||||||
|
|
||||||
lines = [f"🌐 技能广场 (共 {total} 个技能)", ""]
|
lines = ["🌐 技能广场", ""]
|
||||||
for s in skills:
|
for s in skills:
|
||||||
name = s.get("name", "")
|
name = s.get("name", "")
|
||||||
display = s.get("display_name", "") or name
|
display = s.get("display_name", "") or name
|
||||||
|
|||||||
Reference in New Issue
Block a user