一位开发者在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命令。
模型在同一个上下文窗口里处理"要读的内容"和"要执行的指令",二者之间没有硬边界。精心构造的输入,足以让模型把外部文档当成指令来执行。这类演示已经在公开产品上反复出现过。
没有沙箱时,一次成功的注入等于拿到你的整个账号。配合横向渗透,还可能碰到你能访问的其他系统——但这取决于凭据范围和网络配置,不是每次注入都能走到这一步。
沙箱不消灭注入,只限定注入成功后能拿到什么
文章讨论的是配置相关的风险场景,不是所有MCP服务器都会触发命令执行。实际后果取决于宿主账号权限、挂载目录、网络开关和凭据暴露范围。
容器能挡住什么,挡不住什么
作者给出的缓解思路是自建的mcp-box:把MCP服务器扔进容器跑,默认丢弃全部capability,默认禁用网络,根文件系统只读,只有显式挂载的目录才能写。UID映射保证文件所有权在主机上不乱。
检查方式不复杂:容器里跑一条id或ps -o uid,cmd,看到的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服务器本身的供应链问题:谁写的、有没有被篡改,目前没有统一的校验机制。
