.agents/design/code-sandbox/js-one-shot-native-isolation.md
改造前,projects/code-sandbox 的 JavaScript worker 会跨任务复用进程。语言运行时层虽然限制了 eval、动态导入、模块白名单和危险全局对象,但同一进程内的状态污染,以及运行时绕过后的宿主文件、网络、进程能力,仍不能由 JavaScript 自身形成安全边界。
本次改造目标:
no_new_privs 和 seccomp;初始化条件不满足时服务启动失败。SystemHelper.httpRequest 通过 stdin/stdout RPC 交给父 Node 进程执行,复用统一 SSRF、DNS pinning、次数、超时和大小限制。cap_drop: ALL 时仅显式保留 chroot、降权、目录权限和进程回收所需的最小 capability 集合。/sandbox/js API、JS 代码调用方式、模块白名单和返回结构兼容。防御对象是可提交任意 JavaScript 的恶意租户。容器本身仍是最终外层边界;本方案在同一容器内增加进程级纵深防御,目标是即使语言层限制被绕过,也无法:
不声称 chroot/seccomp 等价于虚拟机边界。内核漏洞、Node/V8 原生内存安全漏洞和容器逃逸仍由容器运行时、内核补丁与部署策略承担。
保留 BaseProcessPool 的并发、排队、健康检查、超时和 RSS 监控。JS 池固定 recycleAfterTask=true:
ready。ready worker。因此预热降低冷启动延迟,但任何执行过用户代码的进程都不会回到 idle 池。
新增 Node N-API 原生模块。worker 在回复 ready 前调用其初始化函数:
cwd 启动。chroot("."),随后 chdir("/app/code-sandbox")。PR_SET_NO_NEW_PRIVS。PR_SET_DUMPABLE=0,避免凭据切换重置该标志。JS 与 Python 使用不同 UID/GID,防止两个语言沙箱通过 UID 所有权互相访问资源或发送信号。网络、execve、fork、vfork、clone、clone3 不进入 allowlist。
Linux 下缺少原生模块、chroot 根目录或任一步初始化失败时,worker 不得回复 ready,进程退出,进而使进程池初始化失败。macOS/Windows 只保留本地开发兼容路径,不声明具有 OS 隔离。
worker 的 SystemHelper.httpRequest 不再导入和调用 http、https、dns:
{"type":"http_request","id":...,"payload":...};runSandboxHttpRequest;http_response;父进程按单个任务创建请求计数状态和 AbortController。任务完成、超时或进程异常退出时,中止尚未完成的代理请求,避免用户通过“不 await 即返回”让网络请求脱离 one-shot 生命周期。worker 直接 socket 即使通过语言层逃逸也会被 seccomp 拒绝。
新增 /tmp/fastgpt-js-sandbox,由 root 持有且不可由 JS UID 写入。内部复制 /app/code-sandbox(bundle、原生模块和运行时白名单包)以及 Node 运行必需的设备节点。JS 任务默认没有可写目录;这与当前 JS API 不提供文件写入能力一致。
只读根文件系统部署不能把整个 /tmp 挂载为 tmpfs,否则会遮住镜像内预制的 JS/Python chroot。只为 /tmp/fastgpt-python-sandbox/tmp 提供任务临时 tmpfs。若先 cap_drop: ALL,父服务需要显式保留 CHOWN、DAC_OVERRIDE、FOWNER、KILL、SETGID、SETUID 和 SYS_CHROOT;Docker 默认 capability 集合已包含这些能力。
测试必须在本地真实 Linux Docker 容器中执行,不 mock 原生模块、进程、网络或文件系统:
/etc/passwd、父进程环境或写 chroot 根。net/间接 socket 被内核拒绝;httpRequest 仍经父进程代理,并保持 SSRF/次数/体积/超时与任务结束取消限制。ready 时关闭进程池,确认初始化 Promise 失败、预热计数归零且真实子进程已退出。/sandbox/python API 执行 GHSA-q6ww-4c5x-j2pg 的 _posixsubprocess.fork_exec PoC,确认由 native seccomp 返回 EPERM。