我自己查了 NVD:MCP server 相关记录已到 482 条,85 条是严重级
关于 MCP 安全,网上的文章有一个共同模式:引用一家安全公司的报告,报告引用另一个数字,数字没有出处。我不太想这么写,所以直接查了 NVD 的 API。2026 年 10 月 26 日 20:32 UTC,用关键词「MCP server」查到 482 条 CVE 记录,其中 421 条发布于 2026 年,包含 85 条严重级、215 条高危、136 条中危、44 条低危、2 条未定级;换成更窄的词组「Model Context Protocol」,结果只有 152 条。两个数字差了三倍多,而这恰好是本文想说清的事。
每一条记录背后,都是有人装过的一个 server
一、我到底跑了什么
用的是 NVD 的 REST API 2.0,端点 services.nvd.nist.gov/rest/json/cves/2.0,参数 keywordSearch 加 resultsPerPage=2000。不需要 API key,但有限速:不带 key 时每滚动 30 秒最多 5 次请求。我这个查询跑了两轮,用了两个关键词,都在限速之内。关键词搜索的行为是:在 CVE 记录里做全文匹配,主要是英文描述。这意味着「命中」只代表这条记录的文字里出现了这几个词,不代表这个漏洞的主体是 MCP server。这是所有基于关键词的统计的共同问题,也是我接下来要强调的关键点——你要看原始数据,而不是别人加工过的结论。
# 1) The exact query. No key needed, but NVD rate-limits: 5 requests
# per rolling 30 seconds without a key. Published and fetched
# 2026-10-26T20:32Z.
import json, urllib.parse, urllib.request
def nvd(keyword):
url = "https://services.nvd.nist.gov/rest/json/cves/2.0?" + urllib.parse.urlencode({
"keywordSearch": keyword,
"resultsPerPage": "2000",
})
req = urllib.request.Request(url, headers={"User-Agent": "nvd-check/1.0"})
with urllib.request.urlopen(req, timeout=120) as r:
return json.loads(r.read())
for kw in ("Model Context Protocol", "MCP server"):
d = nvd(kw)
print(kw, "->", d["totalResults"])二、结果,原样贴出来
关键词「Model Context Protocol」:totalResults 152,年份分布 2025 年 23 条、2026 年 129 条;严重度 CRITICAL 26、HIGH 75、MEDIUM 42、LOW 9。关键词「MCP server」:totalResults 482,2025 年 61 条、2026 年 421 条;严重度 CRITICAL 85、HIGH 215、MEDIUM 136、LOW 44、未定级 2。两个关键词的检索时间分别是 20:32:38 和 20:32:59 UTC,同一分钟内。有个细节值得单独说:未定级不是安全的意思,是没有 CVSS v3/v4 评分,而这个桶里的东西往往没人细看。2026 年占绝对多数也符合直觉——MCP 的装机量在 2025 年底之后才真正起来。
# 2) Result, exactly as returned:
# keywordSearch="Model Context Protocol"
# totalResults 152 2025: 23 2026: 129
# severity CRITICAL 26 HIGH 75 MEDIUM 42 LOW 9
# keywordSearch="MCP server"
# totalResults 482 2025: 61 2026: 421
# severity CRITICAL 85 HIGH 215 MEDIUM 136 LOW 44 NONE 2
# Read that again: the broader keyword finds three times as many records.
# Neither number is "the number of MCP CVEs". Both are the number of
# records whose English description happens to contain those words.三、为什么两个数字差三倍:关键词是产物,不是事实
152 和 482 之间的差额,主要来自两类记录。一类是对关键词更敏感的描述:很多 server 的 CVE 描述里写的是产品名加「MCP server」,而不是全称「Model Context Protocol」。另一类是纯噪声:「MCP」这三个字母在别的语境里也成立(比如某些厂商的产品缩写),于是被关键词命中了。所以正确的表述不是「MCP 有 482 个漏洞」,而是「NVD 里有 482 条记录的文字包含 MCP server 这几个词」。前者是一个惊人的论断,后者是一个可复现的事实。很多人引用这类数字时会默认做前一种解读,这是我建议你自己跑一遍查询的最实际的理由。
关键词计数衡量的是用词,不是风险
# 3) Bucket by severity and year straight from the response.
from collections import Counter
def summarise(d):
sev, year = Counter(), Counter()
for v in d["vulnerabilities"]:
c = v["cve"]
year[c["published"][:4]] += 1
m = c.get("metrics", {})
level = "UNSCORED"
for k in ("cvssMetricV40", "cvssMetricV31", "cvssMetricV30"):
if m.get(k):
level = m[k][0]["cvssData"]["baseSeverity"]
break
sev[level] += 1
return dict(year), dict(sev)
# Note the UNSCORED bucket. A record with no CVSS v3/v4 score is not
# safe, it is unmeasured - and keyword searches surface plenty of those.四、四条值得单独读的记录
在这批结果里,有四条特别有代表性。CVE-2025-49596:MCP Inspector 0.14.1 之前版本存在远程代码执行,严重级。教训是调试工具也会进生产——很多人把 Inspector 一直挂在开发机上。CVE-2025-34072:Anthropic 已弃用的 Slack MCP Server 存在数据外泄,路径是自动链接预览(link unfurling),严重级。教训是任何「替你访问 URL」的工具都是一条出网通道。CVE-2025-5277:aws-mcp-server 存在命令注入,构造的提示词就能触发,严重级。教训是提示词文本属于不可信输入,要按查询串对待。CVE-2025-53365:MCP Python SDK 1.10.0 之前的版本有问题,高危。教训是 SDK 也是依赖,SDK 也会收到 CVE。
# 4) What the individual records look like when they matter.
# All of these came back in the query above.
records:
- id: CVE-2025-49596
what: "MCP Inspector < 0.14.1, remote code execution"
severity: CRITICAL
lesson: "the debugging tool you leave running is production"
- id: CVE-2025-34072
what: "Slack MCP Server, data exfiltration via automatic link unfurling"
severity: CRITICAL
lesson: "any tool that fetches a URL on your behalf is an egress path"
- id: CVE-2025-5277
what: "aws-mcp-server, command injection from a crafted prompt"
severity: CRITICAL
lesson: "prompt text is untrusted input, treat it like a query string"
- id: CVE-2025-53365
what: "MCP Python SDK < 1.10.0"
severity: HIGH
lesson: "the SDK is a dependency; the SDK gets CVEs too"
五、把数字变成一条能跑的规则
这些数据如果不能变成策略,就只是内容。可落地的有四条。第一,锁精确版本,「^1.8」这种写法在安全场景里等于不锁。第二,把查询变成一个周期性任务,每周跑一次,然后对 CVE id 做 diff——新增的才是重点,总量变化没那么重要。第三,构建失败条件要明确写:任何已安装 server 或其 SDK 出现 CVSS ≥ 9.0,或者出现任何触碰已安装 server 名称的新 CVE,就挂。第四,每季度清一遍没人再调用的 server,因为真正的风险面不是你装了哪些,而是哪些还在被调用、还在持有凭据。最后提醒一句方法的局限:我查的是 NVD 的公开数据,不是全量漏洞数据库,用词不同结果不同,所以别把任何一个数字当真理,把查询脚本本身当成可复现的工具。
# 5) Turn the data into a policy you can actually run in CI.
# Pin, track, and fail the build on a new critical.
mcp_dependencies:
policy:
pin: exact # "1.8.0", never "^1.8"
track: nvd_keyword # re-run the query weekly, diff the ids
fail_build_on:
- "CVSS >= 9.0 in any installed MCP server or its SDK"
- "any newly published CVE touching an installed server name"
review_quarterly:
- "servers nobody calls any more" # the real risk surface
- "servers with remote endpoints"
runtime:
egress_allowlist: true # unfurling is the CVE-2025-34072 lesson
no_secrets_in_env: true # 88% of servers want credentials
sandbox: "separate process, read-only mounts where possible"
📌 常见问题 FAQ
这些数字是什么时候、怎么取的?
2026 年 10 月 26 日 20:32 UTC,通过 NVD REST API 2.0 查询,参数 keywordSearch,无 API key。两个关键词分别返回 totalResults 152(Model Context Protocol)和 482(MCP server)。查询脚本可以在本文的代码块里找到,可以自行复现。
482 是不是意味着有 482 个 MCP 漏洞?
不是。关键词搜索是在 CVE 记录的文本里做匹配,命中的记录文字包含「MCP server」这几个词,不代表这条漏洞的主体就是某个 MCP server。数字是关键词产物,可复现,但不能直接当作漏洞数量使用。
为什么要用两个关键词?
因为它们差异极大,一个 152 一个 482,正好说明这类统计有多脆弱。只报其中一个数字会得出完全不同的印象,所以两个都报、并解释差异来源,比取平均值或者取大的那个更诚实。
92 条严重级是不是一定要马上处理?
那是我在两个关键词下分别看到的 CRITICAL 数量(26 和 85,已去重前的两组)。要不要处理取决于你的资产清单:已安装、在运行、还持有凭据的 server 才需要排期;从没装过的东西,它的 CVE 和你的风险无关。
我该怎么用这个方法?
把查询脚本放成一个每週运行的任务,保存返回的 CVE id 列表,跟上一轮的列表做差集;然后规定构建失败条件,比如已安装 server 或其 SDK 出现新的 CVSS ≥ 9.0。重点看增量,不要盯着总量。
🔧 推荐工具
📚 参考资料
- NVD API 2.0 — keywordSearch=Model Context Protocol (queried 2026-10-26T20:32Z)
- NVD API 2.0 — keywordSearch=MCP server (queried 2026-10-26T20:32Z)
- NVD — Vulnerabilities API documentation
- NVD — CVE-2025-49596, MCP Inspector RCE (critical, fixed in 0.14.1)
- NVD — CVE-2025-34072, Slack MCP Server data exfiltration via link unfurling (critical)