问一个安全工具"我们受不受影响",多数工具会甩给你一张清单。Blastradius 的做法不一样:它返回一条路径,或者干脆返回零行。
![]()
这套工具叫 Blastradius,建立在图数据库 FalkorDB 之上,作者把它做成了一个能查依赖、查归属、查历史决策的安全 Agent。它最反直觉的地方在于:"No path found"(没找到路径)本身就是最有用的回答。
相似度查不出连接
大多数 Agent 演示靠向量相似度检索上下文。找"听起来像这个的文档"没问题,但回答"这个有漏洞的包,能不能摸到一个对公网开放的服务",就不行了——这是连接问题,相似度证明不了连接存在,也证明不了连接不存在。
图可以。在 Blastradius 里,这个问题就是一次遍历:从安全公告节点出发,沿 AFFECTS 边找到受影响的包,再对每个服务求一条最短依赖路径,路径不为空才返回。
拿 Google 的 Online Boutique 实测,配上真实 lockfile 和真实 OSV 公告,一个 protobufjs 的远程代码执行漏洞在几十毫秒内解析成一条链:
- frontend → checkoutservice → paymentservice
- → @opentelemetry/exporter-otlp-grpc → @grpc/proto-loader
- → protobufjs@6.11.4
对公网入口、负责团队、修复版本,全部出自同一张图。
零行不是失败,是答案
问 Log4Shell,同一条查询返回零行。这不是查不出来,这就是结论:图里没有任何东西依赖 Maven 包,判定为 NOT_AFFECTED,屏幕上那条空遍历就是证据。
再问一个你确实在跑、但版本已经打过补丁的公告,图会解释为什么安全:包在,版本落在受影响范围之外。
判定结果(AFFECTED / NOT_AFFECTED / NEEDS_HUMAN)来自图证据上的普通规则,不由大模型决定。模型是可选的、跑在免费额度上的,只负责选调哪个工具、把结果说成人话。它看不到数据库凭据,也不写 Cypher;读取路径拒绝写操作,数据库层面也强制只读。修复动作只是提案,等人点头。
记忆也是图的一部分
人批准一次修复,这个决定就写回成一个 Case 节点,连到公告、受影响服务和用过的处置手册。几天后另一个 protobufjs 公告来了,三跳遍历就能翻出旧案,Agent 引用它、复用那套手册,手册的成功计数加一。
依赖数据、归属信息、记忆全在一张图里,Agent 之间的交接步骤同样可查。每个租户独占一张 FalkorDB 图,隔离是结构性的,不靠一句"记得加 tenant 条件"。
归属有出处,决策有回执
归属来自 CODEOWNERS,专长来自提交历史,依赖决策连到做出它的那个具体提交。被后续决定推翻的,用 SUPERSEDES 边标出来,所以回答"为什么锁这个版本"时,能说清理由是否还成立。
提交只说改了什么,不说为什么。于是构建步骤会去读每次依赖变更背后的 PR,让 Gemini 抽取决策和写明的原因。模型被框死了:只能复述 PR 里的话,理由为空就保持为空,包名必须在 PR 或提交文本里字面出现才算关联。两条评测守着这条线,第二条在首轮就抓到模型编了个主语——一个改写词,不是真实包名。
拓扑是读出来的,不是手写的
早期作者手写"哪个服务调哪个服务",他自己说这是任何演示里最弱的一环,于是换掉了:Blastradius 直接读项目自己的部署文件。Kubernetes manifest 里一行服务地址就是一次调用,一个 LoadBalancer 类型的 Service 就是一处公网暴露;Compose 文件里裸写的环境变量名要通过 .env 解析,只有真实的 host:container 端口映射才算暴露。
和旧的手写清单对照,发现方式找回了 OpenTelemetry 演示 100% 的边(还多找出 7 条文档从没提过的)、Bank of Anthos 的 100%(它的地址藏在 ConfigMap 和 jdbc: URL 里)、Boutique 的 94%;漏掉的那条根本不在任何部署文件里,评测报告如实写了。
怎么知道它是对的
标准答案不经过图,直接从原始 lockfile、缓存的 OSV 数据、发现的拓扑和 CODEOWNERS 算出来,再和产品结果比对:三个真实项目里每条公告的受影响服务集合与判定、每条返回路径是否真是 lockfile 边的链条、暴露距离、归属、传递调用方、记忆复用、租户与会话隔离。
57 项全过,另有 42 个单元测试和护栏检查,写查询在 Agent 路径上被拒绝。
压测也做了:10、50、100 个 Agent 同时打一张图。读一直快,FalkorDB 串行化写入,写延迟会排队。100 个 Agent 时首轮约 2% 的操作被拒,报的是待处理查询超限——这是数据库在自保,客户端改成带抖动的退避重试,并把每次重试都记进结果,不藏。
还有个"图是不是装饰"的测试:停掉 FalkorDB 容器,界面变红,什么都不答,没有缓存、没有兜底,这是设计如此。重新启动,一切恢复。如果拿掉数据库产品还能跑,那数据库就是装饰;在这里,它就是产品。
同一套工具还以 MCP 服务器形式暴露,Claude Desktop、Claude Code 或任何 MCP 客户端都能直接问图。也能吃 CycloneDX 或 SPDX 的 SBOM:每个组件的 purl 变成 Package 节点,依赖列表变成 DEPENDS_ON 边,之后就是同一张图、同一批遍历;反过来,任何租户都能导出成 CycloneDX 1.5,带上适用的公告。
托管演示跑在 Gemini 免费额度上,所有访客共享一份配额。服务器在所有人之间分配模型调用预算,失败后短暂退避;模型不可用时,同样的工具走确定性路由作答,界面会说明这次是谁答的、为什么。判定从来不依赖模型,所以"我们受不受影响"的答案两种情况下都一样。
下一步是把函数级可达性做到 Go 之外,以及从 OpenTelemetry 追踪里构建 CALLS 边,而不是从部署文件里读。整套东西本地跑,成本 0 美元。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.