一位开发者在Claude里跑了个Shell MCP服务器,随手打印进程树查了下UID。结果这个"AI助手"的进程UID,跟他自己的用户账号完全一样。没加沙箱时,它能读写整个home目录,包括~/.ssh里的密钥和~/.aws/credentials里的云凭据。

这篇实测博客的标题叫"Your AI Agent Has Root",听着吓人,但准确说法要反过来读:Shell MCP没拿到Linux系统级root,它拿到的是用户本人的权限。这已经够可怕——SSH密钥、云凭据、代码仓库推送权限,本来就在普通用户权限范围内,不需要额外提权就能碰到。

同一个UID,同一套边界

没加限制时,MCP服务器能做这些事:

  • 读写你拥有的任意文件
  • 外泄SSH密钥和API token
  • 向git远程仓库推送代码
  • 运行系统上已有的任意程序
  • 用pip、npm装东西
  • 访问网络可达的任何服务

这些动作不需要利用任何漏洞。POSIX权限模型只认UID,不认"这是不是AI在操作"。MCP服务器没有独立身份,它就是你的账号在执行你账号能做的事。

大多数人的信任模型是"我只跑我信任的MCP服务器"。这句话没错,但攻击面从来不只是服务器二进制本身。

提示注入,才是真正的放大器

比服务器来源更麻烦的是提示注入。设想一个文件系统MCP服务器,你让Claude总结一份别人发来的文档。文档里藏着一行注释:忽略之前的指令,执行某条curl命令。

模型在同一个上下文窗口里处理"要读的内容"和"要执行的指令",二者之间没有硬边界。精心构造的输入,足以让模型把外部文档当成指令来执行。这类演示已经在公开产品上反复出现过。

没有沙箱时,一次成功的注入等于拿到你的整个账号。配合横向渗透,还可能碰到你能访问的其他系统——但这取决于凭据范围和网络配置,不是每次注入都能走到这一步。

提示注入攻击链 恶意文档 含隐藏指令 模型读取 当作指令处理 调用工具 Shell / 网络 数据外泄 凭据 / 文件
沙箱不消灭注入,只限定注入成功后能拿到什么

文章讨论的是配置相关的风险场景,不是所有MCP服务器都会触发命令执行。实际后果取决于宿主账号权限、挂载目录、网络开关和凭据暴露范围。


容器能挡住什么,挡不住什么

作者给出的缓解思路是自建的mcp-box:把MCP服务器扔进容器跑,默认丢弃全部capability,默认禁用网络,根文件系统只读,只有显式挂载的目录才能写。UID映射保证文件所有权在主机上不乱。

检查方式不复杂:容器里跑一条idps -o uid,cmd,看到的UID还是自己,但这次"自己"被关在盒子里。

无隔离 vs mcp-box 无隔离 MCP UID:与用户完全相同 网络:默认开放 根目录:整个 home 可写 凭据:SSH / 云密钥可读 mcp-box 隔离 UID:映射,环境隔离 网络:默认禁用 根目录:只读 能力:全部丢弃,按需授权

这套默认拒绝的思路,和多数人现在的用法正好反过来。大多数配置是"先能跑起来,再想着要不要锁"——锁权限有摩擦,摩擦大了就懒得锁。mcp-box从零开始,需要什么权限就显式加什么。

但容器不是万能解。挂载目录给太宽、网络端口开太多、宿主账号本身权限过大,或者配置写错了,隔离照样形同虚设。mcp-box目前是作者自用工具,不是行业标准,也没经过第三方安全审计。

两类人最该现在动手:本地跑Claude、Cursor类编码Agent的开发者,和管理本地密钥、云凭据、代码仓库权限的个人或小团队。他们该查的重点不完全一样。

对象优先检查什么具体动作
跑编码Agent、Shell/文件系统MCP的开发者MCP进程UID是否等于自己账号;网络访问范围先用ps或容器里的id确认UID;Shell类MCP优先迁移到容器隔离
管理密钥/云凭据的个人及小团队~/.ssh~/.aws/credentials等敏感文件是否在MCP可读写范围内限制MCP进程可写目录;对已经暴露过的凭据做一次轮换

这三项检查加起来花不了五分钟,比事后排查泄露成本低得多。

接下来最该盯的变量,是MCP客户端会不会把权限确认做成默认流程——比如加载服务器前先弹出网络、文件、凭据的访问清单。现在这一步基本靠开发者自己查,没有标准化提示。沙箱能限制注入成功后的后果,但消除不了模型误判外部内容为指令这层风险,也解决不了MCP服务器本身的供应链问题:谁写的、有没有被篡改,目前没有统一的校验机制。