前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
AI 热点
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
AI 热点
开发者导航
返回 AI 情报前线
All News · 全部资讯5222
  • AI爬虫根本无法触发你的Analytics统计代码
  • SharePoint高危漏洞CVE-2026-55040正被大规模利用
  • Agent间停止传字符串:共享KV Cache的内存级handoff优化
  • Claude Code 自动化 pipeline 实战:幂等调度与自愈设计
  • 生产级 AI Agent 架构模式:6 种经实际验证的设计
  • OpenAI 上线 GPT-5.6 Sol 超极速模式,吞吐量达 750 tokens/s
  • 语义缓存:大幅降低LLM API成本的隐形成本杀手
  • LLM 成本爆炸的六大架构修复方案
  • RAG 系统如何学会说「不确定」
  • DeepSeek模型集成指南:覆盖主流AI编程工具
  • TradingView信号转自动交易机器人的Webhook架构
  • RAG系统5个隐性成本陷阱
  • 候选人大模型评分系统:OpenAI/Claude/Gemini对比
  • Claude Code 自动生成演示视频:Playwright 录制 + AI 配音自动对齐
  • Qwen3.8-2.4T稀疏专家模型vLLM部署实战
  • ego-lite:专为AI代理设计的共享浏览器,人机并行不抢标签页
  • Cursor官方插件集合发布,含代码审查、团队工作流等实用工具
  • Claude Opus 5 基准登顶,开发者却怀念 Opus 4.8
  • Composio超量定价涨16倍真相:凭证托管成隐形收费项
  • GitHub Spec-Kit:规范优先开发,用可执行规格直接生成代码
  • MCP 缓存安全漏洞:私有结果可能跨用户泄露
  • 用 Rust 徒手实现栈式虚拟机:44 条指令、双后端与零成本安全类型
  • 微软 Copilot Notebooks 支持 Markdown,强化 AI 资料分析
  • 多 Agent 输出重复太吵?用输出去重器解决
  • AI Agent 为何需要向量数据库作为记忆层
  • DeepSeek V4 Pro 上线国家超算互联网,Harness 智能体框架开源
  • 智谱GLM-5.3发布:开源编程能力最强模型
  • 智谱 GLM-5.3 编程能力最强开源模型发布,Qwen3.8-27B 同日开源
  • 英伟达量产全球首款 200G/lane 硅光交换机,功耗降为 1/5
  • 别分类,直接「幻觉」标签:LLM标签推荐新思路
  • Anthropic推出Claude文本水印检测API
  • CoT Prompting 实战指南:何时用、怎么用
  • 阿里Qwen3.8:消费级硬件即可跑出Opus 4.6级性能
  • 什么是AI上下文架构?为什么不建议自建?
  • 阿里Qwen 3.8开源:27B参数上下文达26万token
  • OpenAI推出Computer History:Mac操作记录转为ChatGPT可搜索记忆
  • Grok 4.6 登陆 GitHub Copilot,专为 Agent 编码设计
  • 提升 Claude Code 使用效率的实战指南
  • 换用新模型前,先用历史失败用例回归测试
  • Qwen3.8-27B vs Qwen3.6-27B:架构完全相同,性能提升全赖训练
  • 编程Agent能读git log,却读不到你试错的四次失败
  • AI集成层大规模密钥泄露:Composio等平台暴露数千凭证
  • NVIDIA Nemotron 3.5 Lightning:解决Agent执行层成本与能力矛盾
  • 研究打脸:前沿模型还无法自主做科研
  • AI代理真正学会记住的四层记忆系统
  • Amazon Nova Forge 多轮强化学习奖励函数设计指南
  • GitHub推出覆盖全SDLC的Agent应用
  • SageMaker 联手 Bedrock AgentCore 构建多Agent工作流指南
  • 两阶段语义检索 + 结构化引用:游戏答案类 RAG 架构设计
  • 语音转文字 + 模型网关:知识库流水线的 API 设计实践
  • Google用同态加密让私有AI变为实用技术
  • 已加载 51 / 5222
8.0
热点
AI SCORE
技术实践2026-08-15 10:59

MCP 缓存安全漏洞:私有结果可能跨用户泄露

dev.to · AI#MCP#安全#缓存
Editor brief · 编辑速览

MCP 协议 cacheScope 中 cacheKey 不完整时,私有结果(如用户专属工具目录)可能被后续用户命中,造成跨用户信息泄露,附安全修复建议。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

MCP cacheScope 要解决的是一个微妙的问题:一份响应可能足够"新鲜",但对另一个用户而言却并不安全。

2026-07-28 的稳定版 MCP 规范定义了可复用结果的缓存提示。服务器可以将结果标记为 public 或 private,而 ttlMs 则表示结果可以保持新鲜多长时间。但共享的客户端缓存仍然需要足够的身份信息来隔离私有条目。

如果 Alice 预热了某个缓存,之后 Bob 使用了同一个存储,那么不完整的缓存键就会把 Alice 的结果返回给 Bob。我将这视为一个值得测试的安全边界。

为什么 MCP cacheScope 需要缓存分区

MCP 缓存规范覆盖了以下内容的发现:工具列表、提示列表、资源列表、资源模板和资源读取。

其作用域有不同的含义:

public 结果可以在不同授权上下文之间复用,即使端点需要认证。

private 结果只能在同一授权上下文中复用。

对于用户专属的工具目录,服务器可以这样描述结果:

const server = new McpServer(
  { name: "private-catalog", version: "1.0.0" },
  {
    cacheHints: {
      "tools/list": {
        ttlMs: 60_000,
        cacheScope: "private",
      },
    },
  },
);

这个提示传达了服务器的缓存意图,但不会告诉共享缓存是哪个调用者发起了请求。

缓存键已经需要包含方法名和每一个可能改变结果的参数。授权身份通常在 tools/list 参数之外传递,因此客户端需要为此建立一个独立的分区。

用共享存储重现数据泄漏

危险的结构很小:两个授权上下文、一个响应缓存、没有分区。

const sharedCache = new InMemoryResponseCacheStore();

function unpartitionedClient() {
  return new Client(
    { name: "shared-gateway", version: "1.0.0" },
    { responseCacheStore: sharedCache },
  );
}

我的演示使用两个进程内端点,它们具有相同的 MCP 服务器身份。一个暴露了仅限 Alice 的工具;另一个暴露了仅限 Bob 的工具。这些端点代表了真实认证服务器会产生不同结果的情况。

Alice 先调用 tools/list,将其私有结果放入共享存储。之后 Bob 用相同的参数和服务器身份调用同一方法。

如果没有 cachePartition,查找操作无法区分授权上下文。Bob 会收到 Alice 缓存的工具列表,而他的端点处理零个 tools/list 请求。官方 TypeScript SDK v2 缓存指南警告说,这种配置可能会将一个用户的私有响应体发送给另一个用户。

测试在重现了不安全结果时故意通过。这样可以在无需凭证、网络服务、模型或付费 API 调用的情况下,让失败模式变得可见。

用稳定分区修复 MCP cacheScope

修复方法是为每个授权上下文提供一个稳定的缓存分区:

const sharedCache = new InMemoryResponseCacheStore();

function clientFor(cachePartition: string) {
  return new Client(
    { name: "shared-gateway", version: "1.0.0" },
    {
      responseCacheStore: sharedCache,
      cachePartition,
    },
  );
}

const alice = clientFor("subject:alice");
const bob = clientFor("subject:bob");

现在 Alice 的私有条目与 Bob 的条目分开存储。相同的方法、参数和服务器身份不再解析到同一个私有缓存位置。第二个测试证明两个端点各收到一个请求,每个客户端只看到自己的工具。

我会从一个稳定、不透明的授权身份中导出分区。它必须包含每一个可能改变可见性的维度,如租户、主体、角色或生效范围。原始 bearer token 不是一个好的分区选择:它是秘密材料,且可能在底层主体不变的情况下轮换。

SDK 对 public 条目的处理不同。它们可以在主体分区之间共享,因为服务器明确声明它们可以安全地跨上下文复用。这样既保留了性能优势,又不会削弱私有隔离。

我的审查清单很短:

  • 将依赖授权的结果标记为 private。
  • 当一个存储服务于多个主体时,配置 cachePartition。
  • 用相同的方法、参数和服务器身份测试两个主体。

可运行的 TypeScript 回归示例包含了不安全重现和分区修复。

限制:cacheScope 不是授权机制

cacheScope 控制缓存复用,但不授予访问权限。服务器仍必须认证调用者,并对每个非缓存请求进行授权。

TTL 是一个新鲜度提示,而不是即时撤销机制。如果权限发生变化,等待私有条目过期可能太慢。合规的客户端必须在收到相应的 MCP 通知时使受影响的条目失效,而应用程序仍然需要一个策略来处理该流程之外的授权变更。

其他协议边界也很重要。携带 inputResponses 或 requestState 的多轮重试请求不得缓存。input_required 结果是不完整的,不可缓存。分页按页缓存,每页使用相同的作用域,且不承诺快照一致性。

对于使用私有的、非共享存储的单主体进程,分区可能增加很少的价值。对于网关、桌面主机或通过一个缓存复用用户的服务,我会将分区隔离作为回归测试,而不是配置假设。

你的 MCP 客户端缓存知道每个私有结果属于哪个授权上下文吗?

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
GitHub Spec-Kit:规范优先开发,用可执行规格直接生成代码
下一篇
用 Rust 徒手实现栈式虚拟机:44 条指令、双后端与零成本安全类型