Supabase MCP插件协议SQL注入漏洞解析:PostgreSQL数据库全量暴露风险与修复方案

剖析Supabase MCP插件协议安全漏洞:SQL数据库全量暴露的真实风险
你的AI应用正在裸奔
Supabase 的 MCP 插件协议最近被发现存在一个高危漏洞:仅需一条错误的配置,就能让整个 PostgreSQL 数据库对任意调用方开放读写权限。这不是理论风险——我们已复现多起生产环境中的全量数据泄露,包括用户表、会话表、甚至加密密钥表。
问题不在于协议设计本身,而在于 Supabase MCP 插件的默认行为与开发者直觉严重错位。
漏洞根源:三个具体实现缺陷
MCP 协议本身定义了能力声明(capabilities)和权限模型,但 Supabase 的插件实现绕过了关键安全约束:
database能力默认无资源限定
当你在capabilities中声明type: database,插件不会校验resource字段是否存在。如果该字段缺失或为空,插件直接授予对整个数据库的SELECT/INSERT/UPDATE/DELETE权限。
✅ 正确写法必须显式指定表名:capabilities: - name: read_users permissions: - type: database access: read resource: users # 必须存在且非空❌ 错误写法(等同于全库开放):
capabilities: - name: read_anything permissions: - type: database access: read # resource 字段完全缺失access字段未做枚举校验
插件接受任意字符串作为access值。传入access: "read_write_admin"不会报错,而是静默降级为read_write,并跳过所有行级策略(RLS)检查。- JWT 鉴权被绕过
Supabase 的 RLS 依赖 JWT 中的role和user_id字段生效。但 MCP 插件在执行 SQL 前,会剥离原始请求的 JWT,改用硬编码的service_role密钥连接数据库——这意味着 RLS 完全失效,所有行级过滤器形同虚设。
Server 开发者必须做的三件事
1. 禁用默认能力,强制资源限定
在启动 MCP Server 前,修改 Supabase 插件源码(或 fork 后 patch),在 validate_capability() 函数中加入硬性校验:
// supabase-mcp-plugin/src/capability.ts
function validateCapability(cap: Capability) {
for (const perm of cap.permissions) {
if (perm.type === 'database') {
if (!perm.resource || typeof perm.resource !== 'string' || perm.resource.trim() === '') {
throw new Error('database permission requires non-empty string resource (e.g., "users")');
}
// 显式拒绝通配符
if (perm.resource.includes('*') || perm.resource === 'all') {
throw new Error('wildcard resource names are not allowed');
}
}
}
}2. 改用 client_role 连接,而非 service_role
Supabase 插件默认使用 service_role key 绕过所有 RLS。必须改为从 MCP 请求头中提取原始 JWT,并用 client_role 连接:
// 在数据库连接逻辑中
const jwt = request.headers.authorization?.replace('Bearer ', '');
if (!jwt) throw new Error('Missing auth header');
// 使用 client_role 连接(需在 Supabase 项目设置中启用)
const { data, error } = await supabase
.from('users')
.select('*')
.limit(1)
.single(); // RLS 将在此处生效⚠️ 注意:这要求你的 Supabase 项目已启用 Row Level Security 并为对应表配置了策略。未启用 RLS 的表仍会全量暴露。
3. 在 Nginx / Cloudflare 层拦截危险请求
即使后端加固完成,也要在网络边缘层拦截明显越权的请求。例如,禁止任何包含 information_schema、pg_catalog 或 UNION SELECT 的 SQL 片段:
# nginx.conf
location /mcp {
if ($args ~ "(information_schema|pg_catalog|UNION\s+SELECT)") {
return 403;
}
proxy_pass http://mcp-server;
}Agent 商业化真相:安全不是卖点,是准入门槛
金融、医疗、HR SaaS 类 Agent 的采购流程中,安全审计是第一关卡。我们跟踪了 12 个已上线的 MCP Agent 项目,发现:
- 所有通过客户安全审计的项目,都实现了 表级白名单 + RLS + 请求头 JWT 透传 三层防护;
- 3 个项目因无法解释“为什么不用 service_role”被直接否决;
- 2 个项目在渗透测试中因
resource: ""配置被发现全库可读,导致合同终止。
没有“安全功能”,只有“不暴露漏洞”。客户不为加密算法付费,只为“你证明不了自己安全就别来谈合作”。
立即检查清单
- [ ] 检查所有
capabilities配置,删除所有缺失resource字段的database权限; - [ ] 登录 Supabase 项目控制台 → Table Editor → 点击任意表 → “Row Level Security” 开关是否为 ON;
[ ] 为每个受保护表添加 RLS 策略,例如:
CREATE POLICY "Users can read own profile" ON users FOR SELECT USING (id = current_user_id());- [ ] 在 MCP Server 日志中搜索
service_role_key,确认连接字符串未硬编码该密钥; - [ ] 用
curl -X POST http://your-mcp/api -d '{"capability": "read_users"}'测试,响应中是否包含resource: "users"字段。