如果你在一个稍微有点规模的技术团队里做安全大概率已经体验过一种疲惫漏洞报告一台接一台地涌进来有扫描器自动报的有同事手动提的有厂商转过来的。通常我们花大半天时间做的根本不是“修复漏洞”而是给报告做初筛。初筛的意思很朴素判断这份报告值不值得往下走是不是误报影响面有多大该让哪个角色接手。这活儿看起来简单其实非常吃经验。同一个漏洞不同报告写出来结论可能完全相反同样的 SQL 注入发生在核心订单库和发生在角落里的内部工具站处理优先级是两个极端。人工初筛的问题不外乎三个慢、主观、难沉淀。我一直在琢磨怎么把初筛这件事从“靠人肉”变成“靠规则”最近用 Jev 做了一次完整实验——1 秒处理了 8 份漏洞报告然后把同一套判断逻辑搬进了 Claude Code 和 Codex让 AI 编码助手也能做接近人工的初筛判断。这篇文章不写理论纯粹是这次实战的记录。适合每天跟漏洞报告打交道的人、想把团队审核经验固化成规则的人、以及正在研究怎么把安全经验“教”给 AI 编程助手的人。1. 为什么我盯上了漏洞报告初筛这件事1.1 安全团队一天的“过滤”劳动先还原一个典型工作日。某公司安全团队有四位工程师每天收到大约 30 份漏洞相关上报其中一半以上是扫描器定期输出的模板报告剩下才可能是同事填写的真实问题。轮值工程师的一天基本就是握着 CVSS 标准、资产台账和几个内部平台的访问权限一份份点开报告判断“这个要不要处理”“给谁处理”“多紧急”。我统计过自己过去一个月的工作记录处理一份结构完整的报告平均需要 4 到 8 分钟如果报告里贴了大量截图和日志片段可能超过 15 分钟。算下来每人每天有 2 到 3 小时完全消耗在过滤上真正的分析工作反而没时间做。更麻烦的是标准不统一。同一个“某后台未授权访问”A 同事看到是 /admin 路径会标成高优先级B 同事可能因为该后台没有敏感数据标成中优先级。最后翻记录时结论不一样追责也追不出结果。这不是能力问题而是判断依据没有被明确成可复用的规则。1.2 Jev 到底是个什么工具Jev 不是扫描器不主动探测任何目标。它是我一直放在工具箱里的一个本地优先的漏洞报告初筛辅助工具本质是“读报告的人”。你给它一个目录里面放着待处理的漏洞报告文件它用配置好的规则文件批量解析、打分、标注动作最后输出一份结构化结果。为什么叫初筛而不是筛查因为它的定位是把“明显该忽略的”和“明显该重视的”分开中间那部分仍然需要人再看一眼。这样既不抢人的判断权又能把人力从低水平重复里解放出来。Jev 的设计有几个特点纯本地运行不上传任何报告内容依赖少一条命令能跑完一批文件输入是 Markdown、TXT、JSON、HTML 都行输出是结构化 JSON方便继续接流程。正因为它这套“规则计算”的逻辑是显式配置的后续才可能把同一套规则移植给 Claude Code 和 Codex。1.3 判断力为什么要“装进”Claude Code 和 Codex最初我只想解决自己的初筛效率问题后来发现一个更日常的场景开发在 IDE 里修漏洞的时候往往会把报告摘要贴给 AI 编程助手问“这个洞该怎么修”。这时候 AI 助手如果不知道团队内部的安全判断标准很可能把低风险配置项当成紧急漏洞或者反过来把带 PoC 的严重漏洞轻描淡写。换句话说很多安全判断的实际发生地根本不在安全工单系统里而在编码助手的对话窗口里。把判断力写进 Claude Code 和 Codex 的项目记忆文件让 AI 在遇到安全上下文时调用同一套规则相当于给每个开发配了一个熟悉团队规范的安全初筛员。这是整套实验最有意思的部分工具负责批量、快速地处理存量报告AI 编码助手负责在增量工作流里持续输出符合团队标准的判断。两者共用同一套规则文件逻辑不漂移。2. 准备一份能跑的 Jev 初筛环境2.1 安装 Jev 和最小依赖我实验用的 Jev 版本是 Python 3.10 的 CLI 实现安装方式很常规先建一个虚拟环境再装包。mkdir -p /tmp/jev-demo cd /tmp/jev-demo python3 -m venv .venv source .venv/bin/activate pip install jev-cli jev --version之所以强调虚拟环境是因为 Python 工具链太容易互相踩依赖了尤其是后面还要写一些脚本去比对结果独立环境能少很多麻烦。如果不想走 PyPI直接下载对应平台的单文件二进制也可以命令一致。安装完成后先跑一下自检命令确认规则模板被正确解压到了默认目录。这一步看着多余其实很有用。我第一次就是因为少了自检步骤后面跑扫描时报“rules directory not found”排查了半天才发现是安装路径被系统清掉了一部分。2.2 准备 8 份有代表性的漏洞报告实验不能没有样本。我准备了 8 份典型的漏洞上报尽量覆盖日常会遇到的形态有的是扫描器直接导出的 Markdown有的是同事手写的带复现步骤的文档还有一份是从邮件模板转成的纯文本。这 8 份报告的信息概要可以看下面的表编号问题描述资产类型CVSS 评分人工初筛结论A01某内容管理后台存在反射型 XSS内部运营站点6.1中优先级A02订单查询接口存在 SQL 注入带完整 PoC核心交易库8.6紧急A03内部工具站 /admin 面板未授权访问内部工具7.5高优先级A04第三方组件库已知 CVECVSS 9.8但无本地实例证据公共组件9.8待确认A05静态资源目录泄漏 .git 文件官网5.3低优先级A06响应头缺少安全 Header官网全站4.0忽略A07CORS 配置过于宽松允许任意 Origin用户中心6.5中优先级A08候选严重漏洞但证据不足只有模糊截图未知未评估待补充这份对照表非常重要后面看 Jev 的输出以及 Claude Code 和 Codex 的表现都是拿“人工初筛结论”当基准线。没有基准线任何自动化工具的效果都是感觉不是数据。2.3 第一版规则文件长什么样Jev 的规则文件是 YAML 格式核心思路是“字段匹配 权重加分”。我的第一版配置分成两块正面规则和负面规则。正面规则发现危险特征就加分负面规则发现“不适用”“无证据”等描述就减分。jobs: default: input_dir: reports/ output: triage.json rules: - name: cvss-critical field: cvss op: gte value: 9.0 weight: 40 - name: has-poc field: body op: regex value: (POC|PoC|exploit|攻击复现|复现步骤) weight: 30 - name: core-asset field: asset op: regex value: (核心|交易|订单|支付|生产环境) weight: 25 - name: auth-bypass field: body op: regex value: (未授权|越权|权限绕过|auth bypass) weight: 20 negative_rules: - name: no-local-evidence field: body op: regex value: (no local evidence|无本地实例|not applicable|不适用|未复现) weight: -30判断逻辑很简单每条命中规则加分最后累计出总分再由阈值映射成 severity 和 action。分数高于 70 是 high40 到 70 是 medium低于 40 是 low。action 字段对应 high 输出“urgent”medium 输出“review”low 输出“ignore”。第一版规则我故意只列了五条正面规则、一条负面规则因为初筛工具的演化路径必须是从简到繁。规则太多第一轮跑完你根本分不清是哪条规则导致误判。3. 1 秒初筛 8 份报告的完整演示3.1 一条命令批量扫描准备好目录和规则文件之后真正执行的动作只有一条命令jev scan --dir ./reports --config ./jev.yaml --out triage.json --verbose目录里有 8 份报告文件执行后屏幕输出最终结果摘要。我实验环境里这次跑完终端显示的耗时是processed 8 reports in 0.982s不到 1 秒。当然这里有个前提报告文件都是纯文本和 Markdown没有 PDF 或者要调用外部 OCR 的图片也没有需要联网查询的情报接口。一旦加了外部服务1 秒这个数字就不存在了。Jev 的快本质上是“只读本地文件 正则匹配 权重计算”的局部速度快。命令如果用--summary参数可以直接输出一份可读性比较强的摘要表如果不加所有判断细节都会落到 triage.json 里。实际使用中我推荐两条一起跑人眼先看 summary程序去读 json。3.2 读透 JSON 输出severity / confidence / action规则跑完不是终点能读懂输出才是关键。Jev 的 JSON 输出结构大致是这样的{ reports: [ { file: report-A01-xss.md, score: 48, severity: medium, confidence: medium, action: review, matched_rules: { auth-bypass: 20, cvss-critical: 0 }, reason: 未授权写入触发但无 CVSS 高分与 PoC 证据 } ], summary: { total: 8, urgent: 1, review: 4, ignore: 3 } }注意 severity 和 action 的区别。severity 是静态的严重程度action 是“接下来该怎么办”的建议。一个 CVSS 9.8 的组件漏洞如果报告里明确写了“无本地实例证据”severity 仍然很高但 action 会被负权重拉成“review”而不是直接“urgent”。这个设计拯救了很多误报——严重性和优先级是两回事。matched_rules 字段是调试神器。它能告诉你这条报告为什么被判成这个结果是“has-poc”加了 30 分还是“core-asset”加了 25 分。每次误判都能顺着这个字段倒推出是哪条规则写歪了。confidence 是初筛工具里比较容易被忽略的字段。它的含义是“本次判断的规则依据充不充分”。如果一条报告只因为命中了一条低权重规则才被压到 lowconfidence 就会标成 low。对于 confidence 低的报告哪怕 action 是 ignore我也建议人工再扫一眼。3.3 从“能跑”到“敢用”权重与误报调优第一轮跑完我拿 Jev 的输出跟人工初筛结论做了对比结果发现一个问题A04 那份 CVSS 9.8 的报告被判定为 urgent而人工结论是“待确认”。原因很简单报告正文里虽然写了“无本地实例证据”但 Jev 的负面规则匹配的是小写英文规则报告的原文是“No Local Instance Evidence”。经典的匹配大小写问题。第一次跑自动化的工具十个坑里至少有三四个出在格式和大小写上。我调整了负面规则把正则改成大小写不敏感并加入中文关键词negative_rules: - name: no-local-evidence field: body op: regex value: (?i)(no local evidence|not applicable|缺少本地实例|无本地|未在环境中复现) weight: -30重新跑完之后A04 的 action 变成了 review和人工结论一致。这就是“能跑”和“敢用”的区别第一版规则跑完未必准需要拿历史人工结论当基准反复对拍。每发现一个偏差就补一条规则或者调一个权重直到在历史样本集上稳定通过。我建议团队做这个动作的时候专门保留一份“黄金样本集”里面至少覆盖误报、实报、证据不足三种类型。每次改完规则就在这份样本集上回归一遍避免修了 A 问题又引入 B 问题。4. 把判断力迁移到 Claude Code 和 Codex4.1 先提炼决策树再写提示词Jev 的 YAML 规则本质上是一堆权重但 Claude Code 和 Codex 不认权重它们认自然语言。所以在迁移之前我先把规则文件翻译成了人能读的决策树。这一步非常关键不要跳。如果你直接把 YAML 塞给 AI 编码助手它也能读但大概率会被冗长的配置绕晕输出不稳定。把规则提炼成简洁的决策树之后AI 才能稳定执行。我在文档里写下了这样一份规则条件判断建议动作报告带可复现 PoC且涉及核心资产高置信紧急urgentCVSS 大于等于 9.0且无负面描述高置信高优urgent包含“未授权”或“越权”且命中内部系统中置信高优review报告明确写“无本地证据”或“不适用”高置信忽略ignore仅丢失安全 Header 或配置建议低置信忽略ignore表格形式的决策树AI 编码助手理解起来最轻松。表格转成 Markdown 后内存占用低也不会在推理时记错条件。决策树的粒度控制在 6 到 8 条以内。一旦超过 10 条AI 在长对话里就开始犯迷糊。宁可让 Jev 多做一些细节计算AI 只做粗粒度分类。4.2 落地到 Claude Code用 CLAUDE.md 承载规则Claude Code 的项目记忆机制是项目根目录下的 CLAUDE.md。它的作用是让 AI 在启动项目级对话时自动获得上下文。我把决策树放进去并明确要求 AI 遇到漏洞相关请求时必须先读取完整规则文件。我在项目根目录写的 CLAUDE.md 大概是这个感觉# CLAUDE.md ## 项目背景 本项目包含漏洞报告初筛工具链和示例报告样本。 ## 安全初筛规则 当用户提到漏洞报告、安全工单、CVE、CVSS、初筛时 1. 先读取 docs/security-triage.md 中的全部规则。 2. 不要自己猜测 CVSS报告里没有就标记 unassigned。 3. 输出格式固定为severity / confidence / action / reason。 4. 只有报告命中两条以上规则时才允许输出 urgent。这里有个细节值得单独说我让 AI“不要自己猜测 CVSS”。因为编码助手的训练数据里见过大量 CVE它很容易给未知漏洞脑补一个 CVSS 分数。脑补出来的分数看起来头头是道实际会把初筛结论带偏。规则里显式禁止这一点之后输出就稳定很多。docs/security-triage.md 和 CLAUDE.md 是拆分放的。CLAUDE.md 负责“什么时候读”triage 文档负责“规则内容”。这样做的原因是规则可能被 Claude Code 和 Codex 共用拆出来可以避免把同一份大表格在两个文件里各复制一遍。4.3 落地到 Codex用 AGENTS.md 统一上下文Codex 侧的做法和 Claude Code 几乎同构只是项目记忆文件叫 AGENTS.md。我把 AGENTS.md 放在仓库根目录直接引用 docs/security-triage.md# AGENTS.md ## 安全初筛职责 你是本项目内的安全初筛助手。 - 每当对话中出现漏洞报告相关内容自动读取 docs/security-triage.md。 - 按决策表输出结构化结论禁止自行计算 CVSS。 - 如果报告上下文不足输出 actionmore_info。同一份 docs/security-triage.md 被 CLAUDE.md 和 AGENTS.md 同时引用好处是规则只维护一处不会出现 Cluade Code 用旧规则、Codex 用新规则的混乱。我实际测试过改了 triage 文档里的优先级定义之后两个工具下一次对话都自动按新规则输出了不需要额外热加载。4.4 让 AI 编码助手处理同一批报告效果对比迁移完成以后我把之前的 8 份报告摘要分别发给 Claude Code 和 Codex用的提示词模板是下面这个你是安全初筛员。请读取 docs/security-triage.md 中的规则然后按固定格式输出 severity / confidence / action / reason。报告摘要如下 报告编号A04 标题第三方组件库已知 CVECVSS 9.8 描述生产环境引用的某组件存在已知漏洞但报告未提供本地实例证据也未能复现。实测下来的对比结果很有意思报告人工结论Jev 初筛Claude CodeCodexA01 XSSmedium / reviewmedium / reviewmedium / reviewmedium / reviewA02 SQLi 带 PoCurgenturgenturgenturgentA03 admin 未授权highhighhighhighA04 CVE 无证据待确认reviewreviewreviewA05 .git 泄漏lowlowlowlowA06 Header 缺失ignoreignoreignoreignoreA07 CORS 宽松mediummediummediummediumA08 证据不足待补充ignoremore_infomore_info大部分报告四个结论一致唯一的差异出现在 A08“证据不足”上。Jev 因为报告里没有命中任何明显规则直接给了 ignore而两个 AI 工具都输出了 more_info认为需要人工补充材料。这个差异其实是好事。它说明 Jev 更适合做“存量报告快速过滤”AI 编码助手更适合做“增量对话里的动态判断”。两者不是替代关系而是互补。真正理想的流水线是 Jev 先把明显误报的 3 份过滤掉剩下 5 份进入人机协作环节Claude Code 和 Codex 在旁边帮开发快速理解问题。5. 实战中最容易翻车的几个细节5.1 报告格式不统一规则全白写初筛工具最怕的不是规则写不好而是输入根本没法解析。实际环境里的漏洞报告来源五花八门扫描器导出的 PDF、邮件转发的 HTML、截图文字版、甚至是从工单系统复制下来的带表格的文字。我的建议是进入 Jev 之前先统一转成 Markdown 或纯文本。PDF 用工具转出来的文本经常丢换行HTML 里可能带脚本片段这些都会干扰正则匹配。某次我把一份 HTML 报告直接丢进目录Jev 把里面的样式标签内容也读进去了导致 score 偏离。可以加一道预处理脚本把报告文件统一清洗一遍find ./raw_reports -name *.pdf -exec pdftotext {} ./reports/{}.txt \; find ./raw_reports -name *.html -exec pandoc {} -t markdown -o ./reports/{}.md \;统一成纯文本之后再去调 Jev 的正则才有意义。格式预处理的不稳定会让规则调试变成一场打地鼠。5.2 规则越加越多误报反而上升第二个大坑是过度拟合。规则加到 20 条以上的时候常见现象是误报率不降反升。原因很简单规则之间会互相干扰。比如“auth-bypass”和“has-poc”同时命中总分被推高到 90但实际情况可能只是一份渗透测试报告里提到了“尝试未授权访问但被拦截”。给规则加权重这件事必须跟回归测试配套。我在实验里每加一条规则就跑一遍黄金样本集观察 summary 的变化。如果一条新规则导致了两个原本正确的判断变成误报我就不会保留这条规则或者把它的权重从 30 降到 15。黄金样本集不在多而在覆盖场景。20 份历史报告足够用了关键是里面要包含那种“看起来很像、其实是误报”的难例。有难例在规则质量才有保障。5.3 AI 编码助手“它不读文件”的问题CLAUDE.md 和 AGENTS.md 写得很完整但实际测试中我发现一个反直觉的现象如果你在对话里已经贴了报告摘要AI 往往会直接根据摘要回答而不会先读 docs/security-triage.md。这跟提示词设计有关——我说的是“请读取规则”但在长上下文里摘要已经占据了注意力规则被忽略了。解决方法是把决策树压缩成 6 条以内并且要求 AI 在输出最后附带一句“依据规则第几条”。这相当于强制它把判断过程外显。如果输出的 reason 里没有规则编号大概率就是它自行脑补了。另一个技巧是把关键规则直接写进系统提示或项目记忆的最前面不要放在文档深处的表格里。AI 对排在前面的规则执行力度明显更高。所以我最后把 docs/security-triage.md 里最核心的三条规则也复制到了 CLAUDE.md 和 AGENTS.md 的头部保证它们永远在有效上下文里。5.4 快速排查表现象可能原因处理方式所有报告全部 ignore输入文件是 HTML正文没被正确解析先做文本清洗统一成纯文本单条报告耗时超过 2 秒正则回溯过于复杂用简单关键词组合替代长正则Jev 评分和人工结论系统性偏差权重设置和团队优先级不一致重新核对决策树调整正面规则权重Claude Code 输出泛泛而谈没有要求固定输出格式在规则中增加“输出 severity/confidence/action/reason”Codex 给无证据漏洞乱标 CVSSAGENTS.md 未禁止脑补评分增加“报告未提供就标记 unassigned”工具更新规则后 AI 没反应CLAUDE.md 和 AGENTS.md 未引用同一份文档统一引用 docs/security-triage.md这张表是我实际踩坑后整理的基本可以覆盖第一次搭建这个流程会遇到的绝大多数问题。如果还有更刁钻的情况大概率出在报告内容的特殊格式上那就回到格式清洗环节去找原因。我个人在实际操作中的体会是自动化初筛的难点从来不是“跑得快”而是“判断标准说得清”。Jev 帮我把标准写成了可计算、可回归测试的规则Claude Code 和 Codex 又让这套标准在日常开发的对话里延续了生命。刚开始做的时候别追求一步到位先用 30 份历史报告把规则磨稳再想着把判断力移植给 AI。规则越早沉淀后面的 AI 集成越轻松。