小岛AIAI 航行日志

小岛 / 岛刊社 / 文章

安全 Agent 找出 24 个 Android 漏洞,最难的仍是给结果定级

小岛AI

GitHub Security Lab 的公开案例说明,AI 审计最该抄的不是漏洞数量,而是把可疑发现、PoC 验真和人工定级拆成一条不会自欺欺人的流水线。

AI 安全Agent 工程AI 编程

给代码库接上安全 Agent 以后,最容易发生的一件事,是终端吐出一长串高危发现,团队一边兴奋,一边开始头疼。

这东西到底帮我们找到了漏洞,还是帮我们制造了一座待确认的工单山?

GitHub Security Lab 刚公开了一组很适合拿来对照的材料。他们用开源的 Taskflow Agent 审计 Android 应用,已经披露了 24 个漏洞。数字当然够醒目,但我更在意报告里那句很朴素的话,模型常能找到问题,却不擅长判断问题在真实环境里到底有多严重。

好家伙,这句话比 24 这个数字更值钱。

因为它把 AI 代码安全真正的分工说清了。模型适合把一片复杂代码库里的可疑入口、危险调用链和反常组合先捞出来。至于要不要升级优先级、能不能复现、修复会不会误伤业务,仍然需要一个懂应用的人签字。

这不是给 Agent 泼冷水。恰恰相反,GitHub 这次把它用在了最适合的位置。

漏洞不是靠一句「帮我审计」找出来的

很多人第一次给代码审计接模型,会把任务写成一句大而全的提示词,扫描仓库,找安全问题。然后把结果扔给开发同学。看起来挺省事,实际很像让一个刚看完词典的人去做刑侦,知道很多名词,不一定看得懂案发现场。

GitHub 的做法没这么浪漫。他们把 Android 审计拆成一串有明确边界的 taskflow。先识别攻击者能碰到的入口,再把移动端入口和服务端、桌面端入口分开,之后针对 Intent、导出组件、深链、WebView 这些 Android 常见区域,要求模型逐类检查。

这一步看似只是把 prompt 写细,背后其实是一个很工程的判断。模型不缺常识,缺的是当前代码库里的任务地图。它知道路径穿越和越权调用分别是什么,不代表它知道这个仓库哪一个导出的 Activity 才是真入口,也不代表它能自动把两个看似普通的逻辑缺口连起来。

GitHub 在报告里给出的第一个案例,就落在导出的 MapActivity 上。外部应用可以给它传入控制导入行为的 Intent extras,进而静默替换地图瓦片配置。看起来只是配置项,最终可能变成位置数据被带到外部服务的通道。

GitHub 报告中,导出 Android Activity 的配置片段

图里的 exported=true 不会自己构成漏洞。真正麻烦的是,入口开放、参数可控、后续行为有敏感副作用,这三段链路恰好接在了一起。把这三段都交给一个泛化提示词,模型很容易只报其中一段,或者把一段普通配置误标成高危。

所以第一条可抄的不是某一句 prompt,而是先给审计任务画地图。让 Agent 知道它在看移动端入口,知道要沿着什么攻击面继续走,也知道哪些模式值得优先怀疑。

宽网和窄网,要一起撒

这个案例里还有个小设计,我觉得有点子牛逼。

GitHub 没有只依赖一条严格规则。他们一边让模型按预先列好的漏洞类型做检查,一边保留更宽的探索任务,让模型从代码关系里找不那么标准的组合问题。再通过多次运行,降低漏掉明显问题的概率。

单独用规则清单,优点是稳。你可以确定每个导出组件、每个深链处理器、每个 WebView 桥接点都被走到。缺点也很明显,清单外的连接关系容易被放过。

单独用自由探索,优点是可能碰到意外的链路。缺点同样明显,今天模型关注 A,明天它可能盯着 B,输出稳定性会让人抓狂。

两条线放在一起,才像一个能进工程流程的审计设计。窄网负责覆盖,宽网负责发现。前者保证不漏掉大家早就知道该查的坑,后者留出空间让模型把不相邻的代码片段关联起来。

这也解释了为什么安全 Agent 的价值,经常不在一次跑出多少条结果,而在它能不能把一次研究变成可重复执行的工作流。一个人发现某类 Android 风险后,把入口筛选、检查条件和复现步骤写进 taskflow,下一次就不用重新靠记忆和运气开局。

一条可靠的 AI 审计线,先缩小入口,再枚举可疑链路,回到真实复现

如果你的团队正打算接入这类能力,先别把目标定成「自动审完」。先把高频攻击面拆出来,比如认证回调、文件上传、深链、权限切换和第三方 SDK 边界。每一类都留下可复用的检查任务。能沉淀下来的不是某次模型回答,而是下一次也能跑的审计线。

发现和定级,中间隔着一整个现实世界

报告里最诚实的部分,是 GitHub 直接承认模型在严重度判断上会失手。

模型可能发现一个路径穿越,但没有看见文件路径被限制在外部存储。它也可能看到外部数据可写,就推断应用行为会被改变,却没有继续确认内部存储会不会优先覆盖那份数据。前者会把低影响问题喊得太响,后者甚至可能根本不是一个可利用的漏洞。

安全审计里最贵的,从来不是多发现一条可疑项,而是把不成立的可疑项过滤掉。开发团队的修复时间、发布窗口和安全响应都是真的。每多一条没法复现的高危,下一次真正的高危就更容易被淹掉。

这就是为什么 PoC 很重要。这里的 PoC 不是为了展示攻击花样,而是为了回答三个具体问题。攻击前置条件是否成立,数据流是否真的能走到敏感位置,受影响的版本和用户边界在哪里。

GitHub 的经验是,当模型能拿到原始代码和调试环境,再被要求为报告生成验证步骤,结论会更可靠一些。不过这也不是自动通关。复杂应用常有状态依赖、缓存优先级和多进程行为,模型还是会把看起来合理的推断当成事实。

所以别把 AI 报告直接写进漏洞库的最终字段。把它当作一个候选队列更合适。它负责把人从海量代码阅读里拽出来,把注意力放到值得验证的地方。严重度、修复优先级和披露决策,仍然由了解产品语境的人完成。

有点像代码评审里的 CI。CI 能告诉你测试红了,但不会替你决定这个改动该不该在今晚发布。两件事挨得很近,责任并不相同。

放进 CI 之前,先把队列设计好

很多团队卡在这里。审计 Agent 一跑,几十条结果涌进来,最自然的动作就是接一张表,按模型给的高、中、低排序,然后让值班同学处理。

别急着这么干。

模型给出的严重度可以留下,但更适合叫「初始信号」,不是最终优先级。最终优先级至少还要叠三层东西。攻击面是不是能从外部触达,利用是否需要一个真实成立的前置条件,业务里有没有把损失放大的敏感数据或关键动作。模型很擅长从代码里提取前两层的线索,第三层通常只有业务和安全团队知道。

拿 Android 来说,一个导出的组件、一个深链解析或者一个 WebView 的边界检查,都可能值得看。但是否真的影响用户,往往取决于它能不能跨过登录态、是否能访问私密内容、是否只在调试构建存在,以及补丁会不会已经在某个版本分支里落地。没有这些上下文,CVSS 分再漂亮也容易变成纸面上的热闹。

我更愿意把这条线拆成两个队列。第一个队列只回答「值得人看吗」,可以由 Agent 批量填入入口、调用链、相关文件和它为什么怀疑这里。第二个队列才回答「需要修吗」,由能跑起应用的人补上复现记录、受影响版本、缓解条件和修复建议。

这两张队列之间最好有一道很小的门。没有最短复现路径,或者没有能定位到源码的证据,就不要自动升级成高优先级。这样不是在为人工增加手续,反而是在保护人工时间。安全同学最稀缺的不是会点开报告的手,而是能判断一份报告是否接近真实攻击面的脑子。

报告里提到,模型为了判断一些问题,会被要求生成 PoC 并在调试环境里继续验证。这个动作的价值,不是把自动化做得更炫,而是迫使一条抽象推断接受运行时的拷问。代码说一个路径可能可写,运行时真的写进去了吗。代码说一个参数可控,应用状态和权限组合允许它走到那里吗。这里只要有一处不成立,就该降级或者关闭。

再往前一步,最好把每次人工驳回也记回 taskflow。比如某类报告总是忽略内部存储优先级,下一版任务就要求模型检查覆盖顺序。比如某个深链规则经常被误解,就把有效域名、解析库和真实调用点写进约束。模型不会从一堆被悄悄关掉的工单里自动长出经验,流程会。

这才是我觉得这套公开材料最有启发的地方。它没有承诺一个万能审计员,而是把安全研究里原本很隐性的手艺,入口枚举、威胁建模、验证和复盘,拆成了能逐步加强的工作单元。棒棒的,工程上最可靠的自动化通常就是这样长出来的。

想试,可以先从一条小线开始

GitHub 已经把这套 Taskflow Agent 开源,并给出了移动应用审计的运行入口。官方说明里也写得很直白,运行需要 Copilot 许可,过程会消耗高级模型请求,中等规模仓库可能要跑一到两个小时。

./scripts/audit/run_mobile.sh myorg/myrepo

这条命令不是让你把生产代码一股脑塞进去然后等奇迹。更稳的起点,是挑一个边界清晰的仓库或模块,先确认依赖、日志和结果存放位置,再把输出接到现有安全 triage 流程里。

我会建议每一轮结果至少过四个关口。这个发现对应的攻击入口是否真实存在,模型给出的数据流有没有被代码和环境证据支撑,能否在隔离环境复现,最终才是影响范围和修复排期。

发现可以自动化,验真必须可追溯,定级需要业务语境,关单仍要有人负责。

这样做慢一点吗,当然。可它会让模型找到的好线索留下来,让模型猜错的地方不至于污染整个缺陷池。安全工作最怕的不是慢,是团队对一堆漂亮报告失去信任以后,连真正的问题也不再认真看。

GitHub 这 24 个 Android 漏洞,让我看到的不是「AI 已经可以代替安全工程师」。更像是安全工程师终于多了一个不知疲倦、但必须被严格验收的研究助理。

这角色挺好。别给它一张空白支票,也别只让它做搜索框。把攻击面、检查任务、复现环境和人工责任边界搭出来,它才能真正在你的代码库里干活。

如果团队暂时没有专职 AppSec,也不用等到所有条件齐全才开始。可以选一个已经有测试环境、模块边界清楚、历史缺陷也能回溯的应用,先让 Agent 只做入口盘点和候选归类。人工每周抽一小段时间复核,记录哪些提示稳定有用,哪些只会制造噪音。跑两三轮后再决定要不要扩大范围,比一上来给全仓库开绿灯靠谱得多。

反过来,已经有成熟安全流程的团队也别把它当成另一个告警源。把 Agent 输出接到已有的责任人、服务等级和复现记录里,才不会出现模型很勤快、没有人真正接住的尴尬。AI 审计最理想的样子,不是无人值守,而是每一条自动线索都能找到一个清楚的人工落点。

官方原文和开源任务说明都在 GitHub Security Lab 的报告 中。没有自己跑过这套流程的团队,先从一条小任务开始就够了。

如果你们给 AI 审计结果设计一个人工验收点,会把它放在生成 PoC 之前,还是放在严重度定级之后?