你让 AI 给项目做一次安全检查。
它扫完,甩给你一份报告。
十几条,前面一排红色的“高危”。
你一条都看不懂。
于是你说:那你全修了吧。
这句话,是这件事里最贵的一句。
它一条条往下修,报告上的红色确实清光了。
至于哪几条本来就不成立、哪几条在修的时候顺手弄坏了别的东西,你不知道。
报告变干净了,这是你唯一看得见的事。
一天一个 vibe coding 小技巧,今天就讲清楚:安全扫描之后,到底该怎么处理。

先说一句,这一篇几乎全是能直接复制给 AI 的原话,你不用自己琢磨该怎么开口。想要原版的,看到最后我告诉你怎么拿。
一、先把“发现风险”和“确认漏洞”分开
扫描报出来的每一条,说的都是同一件事:这个地方看着可疑。
它没说这个地方真的能被打穿。
举个最常见的。它报某个位置接收了用户提交的内容,可能被恶意利用。
这句话本身没错。错的是把它当成结论。
一条提醒成不成立,得往后再看三件事——框架有没有自动拦截,代码有没有再次校验,这段内容最后被送到了哪里。
三件都没查清以前,它只能叫“待核实的问题”。
所以扫描结果不是判决书,是一份待核实的清单。
不查清就开修,代价长这样。
那个位置,框架其实早就挡住了。AI 不知道,又在登录那儿加了一层,还把规则写严了。
报告上的红色少了一个。
第二天,手机号里带个空格的老用户,全被挡在门外。
那个漏洞根本不存在,坏掉的登录倒是真的。
这不是说扫描结果不重要。
恰恰相反,真正危险的那几项,很可能就藏在里面。
只是你不能看见“高危”两个字,就让 AI 不分真假地全部开修。
而误判不止落在登录上。支付、权限、数据处理,每一处都可能是原本正常的功能,被顺手改坏。
好在第一步并不难。
先让 AI 只读检查,不许修改代码、配置、依赖和数据。
它必须先告诉你,这一次到底检查了什么。
还要把这次检查对应的代码版本固定下来。
当前是哪一次提交,还有哪些修改没有提交,用了什么扫描工具、什么版本和什么配置,都得写清楚。
否则代码继续改过几轮以后,你连这份结果到底属于哪个版本都说不清。
账号和权限有没有查,用户提交的数据有没有查,密钥和日志有没有查,依赖、第三方服务和公网暴露有没有查。
发现明确证据的,标成已证实。
只有线索、证据还不够的,标成待核实。
已经检查但没有发现问题的,只能写“在当前范围内未发现”。
根本没有检查到的,标成未检查。
不能拿一句“全面扫描完成”,把“当前没发现”“根本没检查”和“已经证明安全”混在一起。
二、把扫描结果变成一份问题账本
检查范围确认以后,再把所有发现写进一份安全审计文档。
每个问题都要有自己的编号。
它出现在哪里,可能影响谁,真被利用以后会发生什么,AI 根据什么认为它有风险,又准备怎么验证,都要写清楚。
已经有保护措施的,也要一并写进去。
这样第二轮复核时,才能判断现有保护到底够不够,而不是重复发现同一个问题。
每一项还要标明当前状态。
刚发现线索时是待核实。
证据能够证明问题成立,改成已证实。
确认是误报或者不适用于当前项目,写清依据以后才能关闭。
开始修复、修复完成和重新验证,也要继续更新状态。
这样你才能看见每个问题到底走到了哪一步,而不是修完以后只剩一句“已处理”。
“已处理”这三个字最省事,也最不说明问题。它是真修好了、还是被 AI 判成误报顺手划掉了,你从这三个字里一点都看不出来。
这份文档里会暴露项目最薄弱的位置,有时还会写到具体的触发方式。
所以它默认是内部文档,不要跟着公开代码一起发出去。
到这里,屏幕上那堆吓人的红色提醒,才开始变成一份能够管理的问题账本。
你可以先把下面这段话交给 AI:
「本轮执行只读安全审计,不修改任何代码、配置、依赖和数据。
先固定基线:项目根目录、当前提交号、未提交改动、技术栈,以及当前生效的需求、架构和安全规则文档。
记录所用扫描工具的名称、版本、配置和执行命令,保证同一版代码可复现同样结果。
审计范围至少覆盖身份与权限、用户输入、敏感数据、密钥与日志、依赖、第三方服务、公网暴露,逐项标明是否已检查。
每条结论按四种状态之一标注:已证实、待核实、当前范围内未发现、未检查。四者含义不同,不得互相替代。
输出一份项目内部的安全审计清单,每项包含编号、风险等级、影响对象、位置、现实后果、判断证据、现有防护、复现方法、验证方法、当前状态。
其中涉及技术判断的结论,各附一句非技术语言的说明。
本轮只交付审计范围、清单和证据,不进入修复。」
三、第二轮不是继续找数量,而是把问题查准
第一轮清单写完,还不能直接动手。
接下来要让 AI 结合当前框架的官方文档、项目里用到的第三方 SDK 文档、项目需求、架构设计和权限规则,把整份清单重新核对一遍。
这里要特别点一句第三方 SDK。
扫描工具认得代码,不认得你装进来的那些别人写好的组件。一条告警到底成不成立,有时候答案根本不在你的代码里,而在那个 SDK 的文档里——它默认开了什么、默认关了什么、哪个版本改过行为。
不翻那份文档,AI 就只能按通用情况猜。
为什么还要再来一次?
因为同一个现象,放在不同的技术框架和业务流程里,结论可能完全不同。
如果 AI 说框架本身已经处理了,不能听完这句话就把问题关掉。
它还得证明:当前使用的框架版本确实提供了这层保护,项目没有把它关掉,这条真实的数据处理过程也确实经过了这层保护。
三项都能拿出证据,才能把它记录成“现有保护已经覆盖”,而不是再写一套重复代码。
告警去重也不能只看文件位置。
同一行代码可能同时存在两种不同的问题,同一个问题也可能经过几条不同的代码路径触发。
让 AI 对照告警使用的规则、用户数据从哪里进入、最后流向哪个危险位置、触发条件和根本原因。
确认这些都指向同一个底层问题,才能合并成一个修复单元。
只看代码表面没有发现,但按照真实业务流程确实能看到别人数据的问题,也不能漏掉。
第二轮真正要做的,是按照证据去重、判断误报、补上业务风险,再重新排顺序。
排序也不能只看工具给出的“高危、中危、低危”。
还要看它有多容易被利用,真出事以后对当前产品的影响有多大。
会影响账号、权限、用户数据、资金或者公网服务的问题,优先处理。
低风险提醒和暂时无法验证的问题继续留在文档里。
不能为了让结果好看,就把还没处理的项目偷偷删掉。
你可以接着对 AI 说:
「结合当前框架官方文档、项目所用第三方 SDK 的官方文档、项目需求、架构设计、数据关系和权限规则,复核这份安全审计清单。
逐条核对告警命中的规则、数据流、触发条件和根本原因。合并修复单元的依据是这些证据指向同一个根本原因,而非位于同一文件。
判定误报或不适用的,写出判定依据。
以“框架已提供防护”为由排除的,需核对框架版本、项目配置和真实数据路径,证明该防护在当前项目中确实生效。
涉及第三方 SDK 的,查对应版本的官方文档,说明该行为属于其默认设置还是本项目配置所致,并给出文档出处。
补充第一轮遗漏的问题,即依赖真实业务流程和权限关系才能发现的那一类。
按可利用性和对当前业务的实际影响重新排序。
本轮只更新审计文档,不修改代码。每一项保留、合并、降级或排除的理由,逐条写明。」
四、真正修复时,一次只处理一个修复单元
清单复核完、处理顺序也确认了,才进入真正的修复。
但这里仍然不能让 AI 一口气全部改完。
动第一项以前,先让 AI 检查 Git 状态。
它要先列出准备提交哪些文件,哪些修改还没有提交,哪些文件没有被 Git 记录。
然后检查暂存内容里有没有存着真实密钥和配置的文件、生产数据、用户信息和不该进入代码仓库的日志。
这些内容没有排干净以前,不准提交。
如果密钥已经写进代码或者提交历史,也不能只把那一行删掉。
先把它记进安全清单,再更换或者作废原来的密钥。
确认提交范围干净以后,才能把当前能够运行的版本保存成一个清楚的检查点,再建立专门处理这轮安全问题的分支。
检查点就是把现在这版代码保存成一个以后能够退回来的节点。
新分支则是单独开一条路处理修改,不和原来的版本混在一起。
接下来一次只处理一个独立的修复单元。
一个修复单元可以对应一条告警,也可以包含几条已经确认来自同一个根本原因的告警。
这样既不会一口气乱改一大片,也不会对同一个问题重复打补丁。
先让 AI 用大白话解释:谁可能利用它,需要满足什么条件,真被利用会造成什么后果。
再让它说明准备改哪些地方,会不会影响现有功能,改完以后怎么证明问题真的关掉了。
到这儿还有两句得追,很多人漏的就是这两句。
第一句:这是不是最好的做法,还有没有别的选择。
AI 给你的方案,通常是它第一个想到的能用的方案。同一个问题往往有好几种改法,有的只动一行配置,有的要改动业务逻辑,代价差得很远。你不问,它不会主动摆出来给你挑。
第二句:这个改动会牵扯到哪些地方,我得重新试一遍哪些功能。
这跟“会不会影响现有功能”不是同一个问题。那一句它可以答“不会”,你就没事可做了。
这一句要的是一张清单:改完以后,你该打开哪几个页面、点哪几个按钮、走哪几条流程。
你不懂代码,看不出改动波及到哪儿。但你能一条条点过去。
这两句问完,你确认方案,它才能动手。
改完也不算完,得拿三样东西出来。
原来那条攻击路径确实被挡住了,扫描工具重跑一遍结论对得上,还有刚才那张复测清单,你自己一条条走完。
三样都有,这一条才算真关掉,写回安全文档,再轮到下一个。
可以这样说:
「本轮只处理安全清单中优先级最高的一个修复单元,其余问题不动。
先说明该单元包含哪些告警,以及触发条件、现实后果和现有防护未能拦截的原因,这部分用非技术语言写。
提交前核对暂存区与提交历史,确认其中不含存放真实密钥和配置的文件、生产数据、用户信息和日志。发现真实密钥时停止提交,报告其出现位置、是否已进入提交历史、需要作废更换哪一个——删除代码中的字符串不足以处理已经泄露的密钥。
给出修复方案:变更文件范围、受影响功能、需要新增或复用的测试、失败时的回滚方式。
同时给出至少两种备选方案,说明各自的代价与风险,以及推荐当前方案的理由。
另外单独输出一份复测清单,写成我可以逐条手动执行的操作步骤,不要只给文件名或函数名。
修改前留下可触发该问题的测试或检查步骤;无法完整复现时,针对这层防护构造一个最小反例。
不改动本单元范围以外的代码,不新增没有真实迁移需求的兼容逻辑。方案经我确认后再实施。
完成后分别提供三项证据:原攻击路径或反例已被拦截、对应扫描结论已符合预期、复测清单全部通过。
将证据写回安全审计清单,然后停下等我确认。」
五、我自己实际是怎么走的
前面四节拆得细,你可能觉得步骤有点多。
我把自己的实际流程说一遍,你就知道它其实只有三轮。
第一轮,只让它扫,扫完写进文档。
这一轮我不看结论,也不让它碰代码。
它只负责把可疑的地方全列出来,一条一条落到那份安全审计文档里。
第二轮,让它把这份文档坐实。
这一轮的关键词是“结合”。
结合当前框架的官方文档,结合项目里用到的那些第三方 SDK 的文档,结合我这个项目自己的架构和权限规则,回头把每一条重新审一遍。
哪条是误报,哪条其实框架早挡住了,哪条得看 SDK 那个版本的默认行为,这一轮才有答案。
而且每一条都要给依据。说误报,得说清凭什么;说框架挡住了,得指出文档哪一句、版本对不对得上。
这一轮做完,那份文档才从“AI 说有这些问题”,变成“已经查过、站得住的问题”。
第三轮,一条条拎出来问。
到这儿才开始谈修,而且一次只谈一条。每一条我固定问四句:
方案是什么。
这是不是最好的方案,还有没有别的选择。
按这个方案改,后果是什么。
会牵扯到哪些环节,我得重新试一遍哪些地方。
四句都问明白,我才说“改吧”。
三轮走下来,最大的变化不是修得多干净,是我全程知道它在干什么。
这三轮里,前两轮一行代码都没动。真正动手是在第三轮,而且是我点头之后。
六、最后
安全扫描扫出很多问题,不代表项目已经没救了。
真正需要警惕的,是你被一长串风险提醒吓住以后,让 AI 立刻全部修掉。
那三轮看起来比“一键修复”慢。
慢的只是前两轮,而前两轮根本没动代码。真正省下来的,是你不用再回头找“到底哪次修改把登录弄坏了”。
安全不是把报告里的红色数字清零。
而是每一个真正存在的问题,都有证据、有方案,也有修复后的验证结果。
如果 AI 给你的安全扫描结果一眼看不懂,就让它从第一项开始用大白话解释,别在没弄清楚以前直接同意修改。
最后我想把这一篇背后那条规矩单独说一遍,因为它不只管安全扫描。
项目出任何问题,都要把“查”和“改”拆成两件事。
查的时候,一行代码都不许动,它只能给你证据;查完拿出方案,你点头,才轮到改;改完还得用同一把尺子,证明问题真的没了、别的地方也没被带坏。
你只要守住一条:没看见证据以前,不说那句“行,你改吧”。