Files
LangBot/docs/review/box-issues.md
Junyan Qin c079f8caad docs(review): refresh box docs; trim issue list to SaaS blockers only
Community self-hosted edition is release-ready, so the box review docs are
updated to current state (date 2026-06-02 + status note) and box-issues.md is
rewritten to keep only the SaaS / multi-tenant / network-exposed release
blockers (S1-S8): unauthenticated control plane, no per-pipeline exec
authorization, unbounded sessions + no reaper, no kernel-level quota, mount
validation gaps (/ + extra_mounts), missing container hardening, lock-around-
cold-start, and the lower-severity follow-ups. Resolved items (tool-call loop
cap, async quota scan, host_path mount allowlist, _is_path_under dedup) moved to
a short "resolved before community release" record; community-only and
pure-cleanup items dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 15:15:39 +08:00

7.2 KiB
Raw Permalink Blame History

Box 系统 — SaaS 发布前阻塞项

更新日期: 2026-06-02 分支: feat/sandbox (LangBot + langbot-plugin-sdk) 相关文档: 架构分析 | Session 作用域 | Runtime 对比 | 测试覆盖 | toB 分析

范围说明

自部署社区版已具备发布条件:默认 stdio 模式、box 为可选项box 关闭 / 不可用时后端、前端、工具、skill、stdio-MCP 均能干净降级(清晰报错、不崩溃);配置向后兼容(旧 data/config.yaml 可直接启动);无新增 ORM 模型、无迁移欠债市场安装失败不会破坏实例。CI 全绿。

本清单只保留发布 SaaS / 多租户 / 公网暴露前必须处理的阻塞项。社区版(可信、单运营者、内网)不受这些项阻塞——它们的风险面在"不可信调用方能直接触达 Box 控制面"或"多租户共享资源"的场景才成立。

已解决(社区版发布前)

处理
工具调用循环无上限 (原 #13) localagent.py 增加 MAX_TOOL_CALL_ROUNDS=128,超限优雅终止(cafef1a3
配额校验同步遍历阻塞事件循环 (原 #10) _enforce_workspace_quota 改 async工作区遍历走 asyncio.to_threadcafef1a3
host_path 挂载白名单 (原 #3 的 LangBot 侧) pkg/box/service.py allowed_mount_roots 白名单,空列表时拒绝一切宿主挂载
重复的 _is_path_under (原 #12) 已去重,仅保留一处定义
重连 / 心跳 / Windows 兼容 / nsjail image 字段 / 前端 Box 状态接入 见上一轮 review 记录,均已合入

SaaS 阻塞项

S1. Box 控制面无认证 — Critical

  • 位置: SDK box/server.py — Action RPC WS (/rpc/ws) 与 managed-process relay (/v1/sessions/{id}/managed-process/{pid}/ws)
  • 现状: 两个 WS handler 在 ws.prepare 后直接服务,无任何 token / 鉴权box 默认绑定 0.0.0.0:5410。任何能触达该端口者可发起 EXEC、创建 session、attach 任意 session 的 managed-process stdin/stdout、甚至 SHUTDOWN。LangBot→box 的 INIT 也未下发任何凭证。
  • 缓解现状: 默认 docker-compose.yamllangbot_box 未把 5410 发布到宿主(爆炸半径限于内网 bridge但 box 挂载了 /var/run/docker.sock,同网络的任意服务(含被攻破的插件)→ 宿主 root。若运营者把 5410 发布到宿主或独立以 0.0.0.0 起 box则完全裸奔。
  • 要求: INIT 时下发 token两个 WS 路由按连接校验query/header。这是 SaaS 的头号阻塞项。

S2. 无 exec 授权模型policy.py 死代码) — High

  • 位置: LangBot pkg/box/policy.pySandboxPolicy / ToolPolicy / ElevatedPolicy 全项目无引用);pkg/provider/tools/loaders/native.pypkg/provider/tools/toolmgr.py
  • 现状: 原生工具(exec/read/write/edit/glob/grep)按"box 是否可用"全有或全无地暴露,无 per-pipeline 的 exec 网关 / 工具白名单 / 沙箱模式 / 权限提升控制。只要 box 可用,任何使用 local-agent + 函数调用模型的 pipeline 都能跑任意 shell。
  • 要求: 接入 policy.py或等价机制按 pipeline 控制是否暴露 exec、可用工具白名单、沙箱网络/只读模式。

S3. 会话资源无界DoS — High

  • #5 session 数量无上限: SDK box/runtime.py _get_or_create_session_sessions dict 无容量限制——可变 session_id 的恶意调用可无限创建容器,耗尽宿主 CPU/内存/PID/磁盘。
  • #8 无定时回收: 过期 session 仅在 _get_or_create_session 时机会性清理,无独立周期任务;一波创建后转静默会永久泄漏容器。
  • 要求: max_sessions 上限(拒绝或 LRU加独立周期 reaper如 60s

S4. 工作区配额无内核级限制TOCTOU — Med-High

  • 位置: LangBot pkg/box/service.py _enforce_workspace_quota(应用层 read-then-checkSDK 侧 workspace_quota_mb 仅记录/透传,无 --storage-opt size= 等内核/FS 限额
  • 现状: 执行前后两次检查之间存在竞态窗口;单条命令(dd/fallocate)可在检查间隙撑爆磁盘,事后检查只能补救。
  • 要求: Docker --storage-opt size= 做内核级限制,或 Redis 原子计数预留式配额。

S5. 挂载校验缺口 — Med-High

  • 位置: SDK box/security.py _BLOCKED_HOST_PATHS_POSIXbox/backend.pyextra_mounts 处理
  • 现状: ① SDK 黑名单仍不含 /(前缀匹配,host_path="/" 可通过,挂载整个宿主 fs用户 home、/usr/opt/tmp 也未拦截。② validate_sandbox_security 只校验 spec.host_path从不遍历 spec.extra_mounts——LangBot 侧 allowed_mount_roots 也只校验 host_path。当前 extra_mounts 仅由 build_skill_extra_mounts 内部填充agent 不可达),但缺乏纵深防御:一旦 S1 的无认证 RPC 被触达extra_mounts 可挂任意宿主路径,两层都不拦。
  • 要求: SDK 黑名单加入 /(或改白名单);extra_mounts 在 SDK 与 LangBot 两侧都纳入挂载校验。

S6. 容器加固缺失 — Med

  • 位置: SDK box/backend.pydocker run 组装
  • 现状: 未设置 --cap-drop=ALL--security-opt=no-new-privileges、非 root --user;叠加挂载 docker.sock逃逸面偏大。
  • 要求: 默认加上上述加固 flag需回归常用 skill 不被破坏)。

S7. 全局锁内执行慢操作(扩展性) — Med

  • 位置: SDK box/runtime.py _get_or_create_sessionself._lock 持有期间调用 backend.start_session()docker run / nsjail 启动 / E2B Sandbox.create
  • 影响: 冷启动镜像拉取数秒、E2B >1s期间串行阻塞所有并发请求——多租户负载下整个 Box runtime 停顿。降级表现是延迟而非失败。
  • 要求: 锁内只做状态检查与注册,容器创建移到锁外。

S8. 其他硬化 / 跟进 — Low

  • #9 SDK box/server.py 直接读 runtime._sessions 私有字段、绕过锁,并发下可能读到不一致状态——应加公共访问方法。
  • #16 pkg/provider/tools/toolmgr.py execute_func_call 按优先级分发plugin/MCP 若有同名 exec/read/write/... 工具会被静默遮蔽——应加命名空间或冲突告警。
  • #4 SDK box/runtime.py INIT/handshake 与 backend 实例化的残留竞态(仅"纯远程 WS box 先启动、LangBot 后连"场景成立stdio/compose 路径下 config 经 env 在 spawn 时已就位,无竞态)——应在 INIT 完成前拒绝业务 action。
  • #11 extra_mounts 在容器创建时固定SDK runtime.py 兼容性检查不含 extra_mounts长生命周期共享 session 后续新激活的 skill 不会挂上(当前缓解:创建时挂上 pipeline 绑定的全部 skill——动态绑定场景需销毁重建或文档说明。
  • #21 集成测试未进 CI容器实际执行、E2B 真机、managed-process WS attach 仅本地可跑。安全关键路径缺自动化覆盖——SaaS 前建议加 Docker-in-Docker CI stage 或合并前手动 checklist。