
Server-Side ReDoS in skill import endpoint via unescaped GitHub URL path in RegExp constructor
快速结论:该问题发生在 LobeChat 自托管服务器中,当通过 agentSkills.importFromGitHub 端点导入技能时,用户提供的 GitHub URL 路径未经过正则转义,直接传入 RegExp 构造函数,导致可被恶意利用造成服务器端拒绝服务(ReDoS)。优先排查服务器版本是否已应用完整修复(escapeRegExp 或非正则匹配方式),而不仅仅是 PR #16332。
问题场景
在自托管 Docker 部署的 LobeChat 桌面应用(Electron)中,任何已认证用户调用 agentSkills.importFromGitHub tRPC 端点,并提交一个包含恶意正则模式(如 (a+)+)的 GitHub URL 时触发。
报错原文
// 恶意输入触发 ReDoS(服务器端无报错,但事件循环阻塞 50+ 秒)
// 调用: POST /trpc/agentSkills.importFromGitHub
// 请求体: {"json":{"gitUrl":"https://github.com/attacker/crafted-repo/tree/main/(a+)+"}}
// 内部构造的正则:
new RegExp('^[^/]+/(a+)+/SKILL\\.md$')
// 备选报错: 输入 [invalid 路径时抛出 SyntaxError
// SyntaxError: Unterminated character class
原因分析
在 src/server/services/skill/parser.ts 的 findSkillMd 方法中(第 204 行),用户提供的 basePath(来自 GitHub URL 路径)仅经过 replaceAll(/^\/|\/$/g, '') 去除首尾斜杠,而未对正则特殊字符进行转义。当 basePath 包含如 (a+)+ 这样的回溯模式时,new RegExp 构造的正则表达式在 .test() 调用时会对 ZIP 包内所有条目路径进行同步匹配,导致灾难性回溯,阻塞 Node.js 事件循环。
环境排查
- LobeChat 版本:v2.1.57(问题存在版本,其他版本可能也存在)
- 部署方式:Self hosting Docker
- 认证状态:已认证用户(无需管理员权限)
- 检查 PR #16332 是否已合并:该 PR 仅修复了斜杠修剪正则的 ReDoS,未添加
escapeRegExp转义
解决步骤
- 确认当前代码状态:检查
src/server/services/skill/parser.ts中findSkillMd方法是否已对basePath进行正则转义。若仅应用了 PR #16332,则修复不完整。 - 完整修复方案(需自行补丁):在
basePath传入new RegExp(...)之前,添加转义逻辑,例如:
const escapedBasePath = basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - 替代方案:将正则匹配替换为精确字符串匹配,避免使用
RegExp构造函数。可参考使用normalizedPath.startsWith(...)或基于path模块的精确路径判断。 - 临时缓解措施:若无法立即修复,可限制
agentSkills.importFromGitHub端点的调用频率,或仅允许受信任用户访问该功能(通过修改权限配置)。
验证方法
修复后,使用以下恶意 payload 进行测试:
POST /trpc/agentSkills.importFromGitHub
Authorization: Bearer
Content-Type: application/json
{"json":{"gitUrl":"https://github.com/attacker/crafted-repo/tree/main/(a+)+"}}
确认服务器不再出现长时间阻塞(正常应快速返回错误或成功,而非 50+ 秒延迟)。同时测试 [invalid 路径是否返回 500 错误而非抛出未捕获异常。
参考来源
相关安全公告:GHSA-35fp-xcr7-6v4h(非公开)
相关 PR(修复不完整):PR #16332 – Avoid OOM When Importing Skills from Large GitHub Repos


