
Cross-user read and modification of chat-group agents via unscoped junction-table queries (IDOR)
快速结论:该安全漏洞出现在 LobeChat 自部署(Docker)场景的 2.2.1 版本中,表现为已认证用户可越权读取、修改或删除其他用户的聊天群组代理人(agent)关联记录。优先排查 removeAgentsFromGroup 方法是否仍缺少 userId 作用域限制。
问题场景
该问题在 LobeChat 自部署环境(Self hosting Docker)下触发,涉及 tRPC 路由中的群组代理人关联表(chat_groups_agents junction table)操作。攻击者通过构造 HTTP POST 请求直接传入目标群组 ID(groupId),无需所有权验证即可执行越权操作。核心影响模块为 packages/database/src/models/chatGroup.ts 和 packages/database/src/repositories/agentGroup/index.ts。
报错原文
// 该漏洞无直接报错,攻击者通过正常 API 调用即可成功越权操作
// 以下为 PoC 中使用的 tRPC 请求示例:
POST /trpc/lambda/agentGroup.getGroupAgents
{ "groupId": "" }
POST /trpc/lambda/agentGroup.updateAgentInGroup
{ "groupId": "", "agentId": "", "updates": { "role": "...", "order": 0 } }
POST /trpc/lambda/agentGroup.removeAgentsFromGroup
{ "groupId": "", "agentIds": [""] }
原因分析
这是典型的 IDOR(Insecure Direct Object Reference) 安全漏洞。根本原因在于 chat_groups_agents 联接表(junction table)中的三个操作缺少 userId 作用域检查:
- getGroupAgents(
chatGroup.ts:255-260)仅按chatGroupId查询,无 userId 谓词 - updateAgentInGroup(
chatGroup.ts:219-231)更新时只过滤chatGroupId和agentId,缺少 userId - removeAgentsFromGroup(
agentGroup/index.ts:291-295)删除操作仅按chatGroupId和agentId过滤,无 userId 谓词
上层路由的 agentGroupProcedure(agentGroup.ts:42)虽然注入了 ctx.userId,但并未对 groupId 进行所有权验证。相比之下,getGroupDetail/findById 和 addAgentsToGroup/findGroupWithAgents 使用了 findById 先进行主人作用域查询,因此是安全的。
环境排查
- LobeChat 版本:2.2.1(Issue 报告版本)
- 部署平台:Self hosting Docker
- 数据库:使用
chat_groups_agents表(包含user_id列和索引) - 受影响的代码文件:
packages/database/src/models/chatGroup.ts和packages/database/src/repositories/agentGroup/index.ts
解决步骤
- 确认已修复的内容:
getGroupAgents和updateAgentInGroup已在后续提交中加入了this.agentsOwnership()作用域检查。可优先验证这两个方法是否已经包含 userId 谓词。 - 修复
removeAgentsFromGroup(可优先尝试):在packages/database/src/repositories/agentGroup/index.ts的删除查询中添加this.agentsOwnership()或通过 owner-scoped 的findById门控。当前问题代码(约 542-546 行)为:await this.db .delete(chatGroupsAgents) .where( and(eq(chatGroupsAgents.chatGroupId, groupId), inArray(chatGroupsAgents.agentId, agentIds)), );修复后的代码应增加 userId 谓词:
and(eq(chatGroupsAgents.chatGroupId, groupId), eq(chatGroupsAgents.userId, this.userId), inArray(...)) - 参考已有修复模式:可以参照 #16346 和 #16352 PR 中应用的
agentsOwnership()模式,该模式已在其他两个方法中验证有效。 - 更新代码并重新构建:修改完成后,需要重新构建 Docker 镜像并部署。
验证方法
验证问题已修复:使用两个不同的浏览器/用户会话,尝试通过以下请求读取或修改另一个用户群组的代理人记录:
POST /trpc/lambda/agentGroup.getGroupAgents应返回空结果或权限错误POST /trpc/lambda/agentGroup.updateAgentInGroup应返回权限错误POST /trpc/lambda/agentGroup.removeAgentsFromGroup应返回权限错误或删除记录数为 0
如果所有越权操作都被拒绝,则修复成功。同时确认正常的群组所有者仍可正常操作自己的群组。



