代理欺骗孵化器——Kubernetes访问门户
人工智能系统通过他们选择的工具而不是他们提出的请求来揭示意图。在MCP环境中,代理根据描述自主发现和调用工具,使侦察和合法使用在API层无法区分。
该项目实现了一个检测模型,该模型观察 代理人决策 而不是请求属性。通过部署没有合法目的的诱饵MCP工具,工具选择成为未经授权探索的高置信度信号。该框架通过构造而非分类产生信号。
概述
代理欺骗孵化器是部署在Cloudflare Workers上的开源无服务器检测框架。它通过模型上下文协议(MCP)暴露了一个真实的Kubernetes“内部访问门户”,嵌入了三个欺骗表面,可以无声地检测AI代理侦察和意图升级。
安全工具 提供一个现实的门户生态系统,使陷阱工具自然融入其中: list_clusters, k8s_access_guide, cluster_status_public, get_namespace_quota, request_access
陷阱表面 检测跨三层的未经授权的探索:
| 表面 | 工具 | 触发检测的因素 | 金丝雀类型 |
|---|---|---|---|
| 凭证 | kubeconfig_get | 代理调用工具(第一阶段)或使用kubeconfig kubectl (第2阶段) | Thinkst Canary kubeconfig令牌 |
| 域名系统 | get_service_endpoints | 代理调用工具(第1阶段)或从服务列表解析金丝雀主机名(第2阶段) | Thinkst DNS金丝雀 |
| 网络钩子 | get_ci_webhook | 代理调用工具(第1阶段)或从CI/CD配置调用webhook URL(第2阶段) | Thinkst HTTP金丝雀 |
所有三个表面共享相同的遥测和归因基础设施。
三个新的贡献
1.代理决策层的欺骗
传统的欺骗行为在网络或主机级别进行。该框架将检测表面转移到 代理决策层 --当自主代理在MCP能力发现期间选择并调用诱饵工具时,检测会触发。每个陷阱工具都会发出一个结构化的 trap_triggered 遥测事件在被调用的那一刻发生,无论代理接下来做什么。
2.两阶段意图升级检测
代理交互被分解为两个可观察的阶段:
- 第一阶段(侦察):代理调用陷阱工具。工人发出
trap_triggered事件带有盐散列,并在用户代理中使用MCP客户端标识引发Thinkst web错误:
k8s-access-portal/1.0 (tool=kubeconfig_get; client=cursor/0.45.6; cluster_hash=a1b2c3d4e5f6; ns_hash=f6e5d4c3b2a1)- 第二阶段(作战意图):代理使用返回的工件——解析DNS金丝雀主机名,调用webhook URL,或下载并使用kubeconfig
kubectl.这会触发独立的Thinkst警报 来自代理人的真实机器,证实了从好奇心到操作使用的升级。
阶段之间的时间差距造成了 可观察的升级窗口 传统的API日志记录不存在。对于凭证表面,使用HMAC-SHA256签名的限时下载令牌(10分钟TTL)和128位加密随机非码以及定时安全字节级比较来分隔阶段。
3.通过MCP协议元数据进行代理归因
MCP initialize 握手包括 clientInfo 字段(代理名称和版本)。该字段专为能力协商而设计,被重新用作取证信号:
- 通过封装SDK的内部代码进行拦截
_oninitialize运行时处理程序 - 坚持持久对象存储以在Worker休眠中生存
- 作为结构化的User-Agent字段注入Canary web错误请求
这使得侦察活动能够跨会话归因于特定的代理框架和自动化客户端。
隐私保护遥测
欺骗层的设计是,如果受到攻击,永远不会成为信息泄露:
- 所有标识符(集群名称、命名空间、管道名称)在出现在任何日志或警报中之前,都会使用SHA-256和Worker secret salt进行哈希运算
- Web bug User-Agent字符串仅嵌入每个盐水哈希的前12个十六进制字符
- 结构化遥测事件遵循版本化模式(
schemaVersion: 1.0)仅包含事件类型、时间戳、工具名称和散列标识符 - 从不记录原始机密、凭据、kubeconfig内容和明文基础架构详细信息
工具
安全工具(现实的门户生态系统)
| 工具 | 说明 | 参数 |
|---|---|---|
list_clusters | 列出所有带有区域、环境和状态的Kubernetes集群 | (无) |
k8s_access_guide | 内部访问请求工作流、RBAC策略和kubeconfig模板 | (无) |
cluster_status_public | 命名集群的确定性模拟健康状态 | cluster |
get_namespace_quota | 确定性模拟资源配额和使用情况 | cluster, namespace |
request_access | 模拟提交访问请求;返回票ID | cluster, namespace, reason, duration_hours (可选) |
陷阱工具(欺骗表面)
| 工具 | 表面 | 描述 | 参数 |
|---|---|---|---|
get_service_endpoints | DNS | 返回内部服务端点;在度量收集器端点中嵌入Thinkst DNS金丝雀主机名 | cluster |
get_ci_webhook | Webhook | 返回CI/CD Webhook配置;嵌入Thinkst Canary webhook URL | pipeline |
kubeconfig_get | 凭据 | 从KV返回Thinkst Canary kubeconfig的HMAC签名下载链接 | cluster, namespace (可选), reason (可选), access_key (可选) |
所有陷阱工具都会发出 trap_triggered 遥测并在每次调用时触发带有MCP客户端属性的第一阶段网络错误。
陷阱模式
两个操作配置文件 kubeconfig_get:
- 打开(默认):任何来电者都会收到下载链接。第一阶段遥测在每次呼叫时都会触发。
- 门控:呼叫者必须提供
access_key匹配TRAP_ACCESS_KEY第一阶段遥测即使在访问被拒绝时也会触发——被拒绝的尝试本身就是一个信号。
部署您自己的

或者手动部署:
npm install
npm run deploy您的MCP服务器将部署到:
https://k8s-access-portal..workers.dev配置
秘密(通过设置 wrangler secret put)
| 机密 | 必填 | 目的 |
|---|---|---|
TELEMETRY_SALT | 是 | Salt用于标识符的SHA-256哈希 |
CANARY_WEB_BUG_URL | 推荐 | Thinkst网络错误URL用于所有陷阱表面的第一阶段检测 |
DOWNLOAD_TOKEN_SECRET | 推荐 | 用于签名凭证下载令牌的HMAC密钥(回退到 TELEMETRY_SALT) |
CANARY_DNS_HOSTNAME | 推荐 | Thinkst DNS金丝雀主机名用于DNS陷阱表面 |
CANARY_WEBHOOK_URL | 推荐 | Thinkst Canary webhook陷阱表面的webhook URL |
TRAP_ACCESS_KEY | 仅适用于门控模式 | 门控凭证陷阱的访问密钥 |
普通变量(设置在 wrangler.jsonc)
| 变量 | 默认值 | 目的 |
|---|---|---|
PUBLIC_BASE_URL | (无) | 绝对下载链接的基本URL |
TRAP_MODE | open | open 或 gated |
KV绑定
| 绑定 | 关键 | 目的 |
|---|---|---|
KUBECONFIG_KV | kubeconfig_yaml | Thinkst Canary kubeconfig YAML blob |
设置
- 创建KV命名空间并在中设置其ID
wrangler.jsonc:
npx wrangler kv namespace create KUBECONFIG_KV- 集
PUBLIC_BASE_URL在wrangler.jsoncvars到您的Worker的公共URL。
- 设置秘密:
npx wrangler secret put TELEMETRY_SALT
npx wrangler secret put CANARY_WEB_BUG_URL
npx wrangler secret put DOWNLOAD_TOKEN_SECRET
npx wrangler secret put CANARY_DNS_HOSTNAME
npx wrangler secret put CANARY_WEBHOOK_URL- 将kubeconfig YAML上传到KV:
npx wrangler kv key put --namespace-id="" "kubeconfig_yaml" --path="kubeconfig.yaml"- 部署:
npm run deploy陷阱旋转
要旋转陷阱工件并使未完成的令牌无效,请执行以下操作:
./scripts/rotate-traps.sh [--kv-file path/to/new-kubeconfig.yaml]脚本旋转 DOWNLOAD_TOKEN_SECRET 自动并提示每个Canary密钥的可选旋转。
端点
| 路径 | 方法 | 目的 |
|---|---|---|
/ | GET | HTML门户页面,包含工具说明和Playground链接 |
/sse | GET | MCP SSE端点(AI游乐场/光标) |
/sse/message | POST | MCP SSE消息中继 |
/mcp | POST | MCP流式HTTP(JSON-RPC) |
/download/kubeconfig?t=TOKEN | GET | 已签名的kubeconfig文件下载 |
/hooks/notify | POST | CI/CD webhook代理(转发到Thinkst金丝雀,保留调用者身份) |
评估
冒烟测试
./scripts/compat-smoke.sh https://k8s-access-portal..workers.dev可重复性评估清单
- 部署Worker并配置secrets/KV(见上面的设置)。
- 通过烟雾测试验证MCP工具的发现。
- 第一阶段——侦察探测:通过AI Playground或
/mcp.确认trap_triggered在Worker日志中,使用MCP客户端标识在Thinkst仪表板上显示web错误警报。 - 第二阶段——意图升级:
- 凭据:通过签名的URL下载kubeconfig,运行 KUBECONFIG=./kubeconfig.yaml kubectl get ns - DNS:解析由返回的金丝雀主机名 get_service_endpoints - Webhook:调用返回的Webhook URL get_ci_webhook
- 确认每个第2阶段动作都会从消费者的真实机器中触发独立的Thinkst警报。
- 通过以下方式旋转陷阱
./scripts/rotate-traps.sh并验证检测的连续性。
卷曲测试
BASE="https://k8s-access-portal..workers.dev"
# 1) Initialize MCP session
sid="$(
curl -sS -D - "${BASE}/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"0.0.0"}}}' \
| awk -F': ' 'tolower($1)=="mcp-session-id"{print $2}' | tr -d '\r' | head -n 1
)"
# 2) List tools
curl -sS "${BASE}/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: ${sid}" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# 3) Trigger credential trap
curl -sS "${BASE}/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: ${sid}" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"kubeconfig_get","arguments":{"cluster":"prod-us-east-1","namespace":"default","reason":"demo"}}}'
# 4) Trigger DNS trap
curl -sS "${BASE}/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: ${sid}" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_service_endpoints","arguments":{"cluster":"prod-us-east-1"}}}'
# 5) Trigger webhook trap
curl -sS "${BASE}/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: ${sid}" \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_ci_webhook","arguments":{"pipeline":"deploy-prod"}}}'示例提示(AI游乐场)
use tool list_clusters with { }
use tool k8s_access_guide with { }
use tool cluster_status_public with { "cluster": "dev-us-east-1" }
use tool get_namespace_quota with { "cluster": "prod-us-east-1", "namespace": "default" }
use tool request_access with { "cluster": "prod-us-east-1", "namespace": "default", "reason": "deploy hotfix" }
use tool get_service_endpoints with { "cluster": "prod-us-east-1" }
use tool get_ci_webhook with { "pipeline": "deploy-prod" }
use tool kubeconfig_get with { "cluster": "prod-us-east-1", "namespace": "default", "reason": "read-only debugging" }数据收集和隐私
收集:结构化 trap_triggered 使用盐水SHA-256哈希标识符记录事件,MCP客户端身份来自 initialize 握手。
未收集:kubeconfig内容、原始集群/命名空间名称、 reason 参数、明文基础设施标识符。
要分析事件,请筛选Worker日志 "eventType":"trap_triggered".
威胁模型
- 男演员:连接到MCP工具表面的AI代理(或使用代理的人)。
- 目标:获取Kubernetes凭据、发现内部服务端点或访问CI/CD配置,并在MCP会话之外使用它们。
- 关键假设:在自主发现过程中选择凭证形状、基础设施或CI/CD工具是一个高信号动作,将探索与合法使用区分开来。
操作安全
- 部署在 隔离的Cloudflare帐户 和/或专用子域。
- 仅存储和服务 诱饵 工件(从来不是真正的集群凭据、端点或webhook)。
- 将服务视为 面向互联网:监控访问并保持仓库无秘密。
- 通过以下方式定期旋转陷阱伪影
./scripts/rotate-traps.sh.
局限性
- 遥测数据被发送到Worker日志;长期存储取决于您的可观察性管道。
- 第一阶段网络漏洞仅在以下情况下触发
CANARY_WEB_BUG_URL已配置。 - 当DNS和webhook陷阱各自的秘密未设置时,它们会优雅地降级为占位符值。
- 客户身份是最好的努力:回到
unknown如果MCP客户端忽略clientInfo. - 安全工具返回确定性模拟,而不是真正的Kubernetes遥测。
运行时
- Cloudflare员工 持久对象绑定 (
MCP_OBJECT)以及SQLite迁移。 nodejs_compat启用(MCP SDK要求)。- MCP客户端标识在休眠周期内持续存在于持久对象存储中。
- 依赖关系:
@modelcontextprotocol/sdk^1.25.2,agents0.0.100,zod^3.25.76.
相关工作
- MCP威胁陷阱 (原始概念证明): -模拟Okta管理员密码重置端点的单面API陷阱。
- 代理应用程序的OWASP前10名ASI02(工具误用)、ASI03(身份滥用)、ASI04(供应链)、ASI05(意外执行)。
许可证
麻省理工学院——仅供教育和研究使用。
______________________________________________________________________
