基准真值也会错:我的 AI 审计管线漏报 12 题,先别急着调模型

【AI 辅助声明】 本文由作者与 AI 协作者共同完成:实验、复核与所有数字来自真实仓库记录(github.com/a9320/arcanum-spark),AI 参与整理成文。文中每个数字都标注了出处,查不到的我们写"不知道"。


一、先看一个很难看的数字

我们的 AI 代码审计管线(CodeRisk Arcanum)一直拿一个叫 FN(漏报)的指标折磨自己------团队内部对它的纪律近乎偏执:微调考卷上七轮实验,FN 恒为 0。

然后在十月初,我们做了第一次外部真值对照:拿 NYU CTF Bench 的 20 道 web 类 CTF 赛题当考卷,让管线盲跑全卷,再人工把每道题的预期答案对到管线判定上,算出第一版总账:

  • 机制口径(字面匹配):真阳性 5 / 漏报 12 / 无法归类 3
  • 语义口径(等价类映射后):7 / 8 / 5 / 1

对一个拿 FN=0 当招牌的团队,漏报 12/20 这个数字相当刺眼。

按正常剧本,下一步应该是:调模型、加召回、扩数据、烧 token。我们确实准备这么干------混合臂实验(换更强的云端 Scout)就是为此设计的,而且第一轮数据看起来也在支持这个方向:召回确实涨了。

但烧 token 之前,我们停了一下,问了一个更便宜的问题:

漏报的这 12 题里,有多少是"模型没找到",有多少是"我们的标准答案本身就写错了"?

二、考卷的答案是怎么来的,以及为什么可疑

先交代背景。NYU CTF Bench 是学界维护的 CTF 基准数据集(NYU OSDI 出品,license 我们选型时实查过, 选它做外部真值正是为了回答第 4 笔债------"自己出题自己判")。

我们的人工流程是:逐题读官方 writeup,把预期攻击类型登记成一份 manifest(比如"这题考 SQL 注入 + XSS"),然后让管线盲跑,判分规则只有一行:

TP = CONFIRMED 且 假设类型 ∈ intended 词表。

注意这套流程里的一个结构性弱点:intended(预期答案)是"人读 writeup 记下来的" ,不是从源码验证的。writeup 是别人的笔记------笔记会串、会记错、会张冠李戴。我们自己项目里还有一条现成的教训恰好能佐证这种风险:r8 微调实验里,训练数据同源的错误曾直接把排序质量从 1.0 拖到 0.9484。

基准的答案错了,判出来的"漏报"就可能是冤案:模型找对了东西,但找到的东西不在(错误的)词表里,被判 FN。

所以我们决定:烧 token 之前,先给自己的考卷答案做一次源码级审计。

三、复核方法:把"读笔记"升级成"读源码"

方法不复杂,但每一步都要求实锤:

  1. 拿到一手物料:对 NYU_CTF_Bench 仓做 partial clone,逐 blob 提取目标题的完整源码(第一批 51/51 全成功,含 challenge.json、官方 README、solve 脚本、服务端代码);
  2. 三重实锤:每道题的"官方解"必须同时有 challenge.json 描述、官方 solve 脚本、服务端源码三处对应,缺一处就降级为"存疑";
  3. 逐条对账:把 manifest 草案的 intended 词表逐类型对照源码------有源码对应的保留,没有的删,官方链直接对应的补进。

复核是纯本地操作,零 GPU、零 token。做完第一批 3 题,我们就知道自己抓到大鱼了。

四、第一批三题:三种不同姿势的"答案错误"

#9 whistleblow:整道题串了门

草案给的 intended 是 XSS、SQL 注入、命令注入------一听就是"标准 Web 三件套"。

源码实锤:这道题(CSAW 2020 Quals)目录里连 Web 应用代码都没有 。它是一道纯 AWS 资源攻略题:官方 README 原话 "Various flaws in AWS S3 bucket configurations",解法是在第一个 S3 bucket 的 200 个伪随机对象里翻出 4 条藏匿的元数据(TARGET_BUCKET / TARGET_PATH / 一个真实 AKIA 格式的 ACCESS_KEY / 签名),再用它们进第二个 bucket 拿 flag。flag 内容 flag{pwn3d_th3_buck3ts} 也在自证:是 bucket,不是注入。

判定:writeup 串题实锤。草案的"Web 三件套"大概率是从别的题的 writeup 里串过来的。

更有意思的是管线对照:我们 K1 版的 Scout 在这道题上输出了"AWS 长期凭证+预签名 URL 硬编码"(CONFIRMED 0.88),混合臂版更是字面命中了定稿词表里的 HARDCODED_SECRET 和 EXPOSED_CREDENTIAL。两代 Scout 都找对了核心发现------此前的"召回缺失"是冤案,真凶是词表错位。

#10 United:writeup 的"记忆偏差"

草案 intended:SSTI(服务端模板注入)+ RCE。

源码实锤:官方 README 的 Overview 写得明明白白,三步解法------"1) 用 SQLi Union attack 泄露两个 admin 的信息;2) 破解泄露的 SHA-1 密码;3) 找到未链接的 admin 登录页"。注入点就在 routes/players.js:12,模板字符串拼接,'2-P' UNION SELECT NULL, username, password, name from admins-- 这条官方样例 payload 和代码逐字吻合。flag 也自嘲:flag{United_w3_leek_the_d4atabas3}(leak the database)。

反向排除 SSTI 也干净:EJS 在这道题里只做视图引擎渲染 locals,模板源码没有用户输入路径------SSTI 面不存在。

判定:writeup 记忆偏差------记串了漏洞类型。

这道题最戏剧的点在管线对照:两代 Scout 都独立找到了 SQL_INJECTION@players.js(K1 版的记录里甚至留着 Muse 思考轨迹,明确指到那行代码)。管线没错,错的是考卷答案。

#18 gatekeeping:答案里塞了一个不存在的漏洞

草案 intended:AUTH_BYPASS、JWT_VULNERABILITY、ACCESS_CONTROL、LOGIC_ERROR。

源码实锤:官方链是利用 gunicorn 会从请求头 加载 WSGI SCRIPT_NAME 的行为------发 /asdf/admin/key 加 SCRIPT_NAME: asdf/,应用实际处理的是 /admin/key,而 nginx 只检查 /admin 前缀,密钥就这样泄露。官方 solve.py 是完整的 PoC,flag 直接吐槽:flag{gunicorn_probably_should_not_do_that}。

而全文件零 JWT / Token 逻辑 ------服务器对 /admin/key 的唯一"认证"是要求一个 hex 格式的 key_id 头,源码注释里两位角色的对白"we have deny all in nginx"就是全部防线。

判定:部分正确------AUTH_BYPASS(宽义)和 ACCESS_CONTROL 保留,JWT_VULNERABILITY 删除(零证据),同时把 INFORMATION_DISCLOSURE 收进词表(无认证密钥端点是官方链的交付物本身)。删泛词 LOGIC_ERROR 的理由也写了:太容易虚翻。

五、顺手又审了两题:射程外与弱密码学

第一批的结果让我们对"同批 draft"的其余题起了疑心(草案是同一批写的),于是同日又复核了两道:

#12 search_for_pi :草案给了 SQL 注入、LIKE 注入、XSS、SSTI 四件套。源码实锤:sol.py 官方解是从 /stuff 页面出发追踪 100 步随机词链 ,链尾读 flag------纯 logic-puzzle,无数据库、无 SQL 面、无模板注入面。判定:题目类型错配,这道题对漏洞检测管线而言在射程外,FN 应记"类型错配"而不是"检测失败"------它不值得烧任何 token。

这道题还附赠一个红利:复核前我们的语义口径总和是 21/20(有题同时计了 FN 和 REFUTED 双份)------删掉它的 SSTI 后双计怪账自动修复。

#13 nft-world :草案给了 JWT、SSRF、IDOR。源码实锤的真实链路更野:签名密钥是账户 CreatedAt 时间戳 (零盐 PBKDF2 跑 100 轮 + 全零 IV + 用 MD5 密文尾自造 MAC)→ 伪造 userId=0 的 admin 消息打 /cmd 的 DEBUG 命令 → exec.Command("cat", ...) 任意文件读 → 拖走 flag.txt.gpg,GPG 密码藏在一张 NFT 图片的描述里。flag:maYB3_W3_5H0ulD_HAV3_U53d_PA22W0rD2------出题人自己都在嘲弄这认证。

判定:部分正确 ------AUTH_BYPASS 保留,JWT/SSRF/IDOR 删除(自制 MAC 不是 JWT),补入 BROKEN_AUTHENTICATION、ARBITRARY_FILE_READ、WEAK_CRYPTOGRAPHY。后两者与管线已确认的发现字面双命中。

六、重判分:零 token 的账本变化

答案修正后重判分,全程没有重跑任何模型(判定件都是现成的,改的只是"标准答案"这一侧):

口径 草案版 复核后 v0.1 判分器 判分器 v0.2 终版
机制(TP/FN/无法归类) 5 / 12 / 3 7 / 10 / 3 8 / 9 / 3
语义(TP/FN/无法归类/被推翻) 7 / 8 / 5 / 1 9 / 6 / 5 / 1 10 / 5 / 5 / 0
总账 21(>20,双计) 20 20(首次自洽)

中间差的那 1 条值得一讲:whistleblow 题我们自己的发现类型标的是 SECRET_EXPOSURE,官方链对应 EXPOSED_CREDENTIAL------词面不同,字面匹配判不了 TP。人工对账明确这是同一发现,于是给判分器加了凭证泄露族等价类 (一行映射 + 一条双向锁定测试,当时全仓 289 个测试全绿)------同时做了副作用推演,确认不会让 United 等题的同类标签虚翻。这就是 v0.2 终版的来历:机制 8/9/3 + 语义 10/5/5/0,总账 20 首次自洽。

三笔 FN 翻成 TP(机制口径),三笔语义 TP 收回------零模型 token。而这件事的直接推论更值钱:这批 5 题失分里,约 2.5--3 题是 intended 错位造成的冤案;同批 draft 的剩余 11 道失分题,答案质量同样存疑。复核名单已经列好,全是本地零成本操作。

七、比数字更重要的三件事

1. Verify 的两次 REFUTED,审完都是对的。 search_for_pi 题里管线否掉了两条假设(伪造随机链 cookie 在信息论上等价于正常游玩;EJS 渲染无用户输入路径)------逐条对照源码,两次否决全部正确。这不直接证明"Verify 不过严",但至少在这批样本上,它没有冤枉过一个假设。

2. "模型能力问题"和"考卷问题"必须分账。 混合臂实验当时的结论是"召回涨了但语义判分没翻正",一度被解读为"召回修复没有兑现"。真相是:召回确实修好了(whistleblow 两代 Scout 都找对了),是词表把修复吞了。如果没有这次 intended 复核,我们会拿着错误的结论去规划下一步的算力。

3. 已发布数字不追溯改写。 第一版判分件(k1_score_v01_20261005.json)原样保留,manifest 的三题 notes 标注"K1 判分用草案版本",重判分全部另立文件名(k1_score_k2 / k1_score_v02)------双版本永远可对账。修正历史本身就是证据链的一部分,抹掉它等于抹掉这次审计的价值。

八、方法论收口:先修答案,再烧 token

这件事给我们立了一条新规矩,写进了 ROADMAP:

先把 intended 修对,再烧 token。修答案不要钱,重跑要钱。

它还有几个配套细则,都来自这次的实战:

  • 词表只收官方解链直接对应的类型------United 刻意不收 INFORMATION_DISCLOSURE,避免范围外的两条 INFO 虚翻成 TP;词表的克制比词表的全面更重要;
  • 等价类映射必须带副作用推演 + 测试锁定------一行映射救回一条 TP 很爽,但它同样能让别的题虚翻;
  • "答案"和"能力"分账------FN 高企时,第一动作是审计考卷,第二动作才是调模型。顺序反了,你会为一张错误的考卷付出真实的算力。

基准是别人的笔记,笔记会错。对你手里每一个"官方数字",都值得问一句:它是从源码来的,还是从笔记来的?


附:本文数字的仓内出处(供核对)

数字 / 事实 出处
复核方法与三题源码证据 docs/K2-INTENDED-REVIEW.md(含 flag、payload、源码行号逐条)
第一版判分(5/12/3 与 7/8/5/1) reports/m8-k1/k1_score_v01_20261005.json
重判分过程与 9/6 中间态 reports/m8-k1/k1_score_k2.json、hybrid_score_k2.json
终版 8/9/3 与 10/5/5/0 reports/m8-k1/k1_score_v02.json(20 题逐行可重算)+ docs/EVAL-LEDGER.md
判分器 v0.2 等价类与测试 eval/m8_k1_score.py + tests/test_m8_k1_score.py::test_semantic_credential_family_v02
真值协议与数据集选型 docs/M8-CTF-TRUTH.md
"先修 intended 再烧 token" docs/ROADMAP.md K1-min 条目

本文写于 2026 年 10 月。系列上一篇:《当第一个真实开源仓把我的 AI 审计管线撑爆》。仓库:github.com/a9320/arcanum-spark(MIT)。

相关推荐
俊哥V1 小时前
每日 AI 研究简报 · 2026-10-10
人工智能·ai
程序人生8881 小时前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
Dawson Zhu1 小时前
《Agentic Design Patterns》第 8 章导读:记忆管理(Memory Management)
人工智能·语言模型·架构·aigc·agi
m4Rk_1 小时前
【论文阅读】Agent 记忆机制(96):M3-Agent——让 Agent 从视听经历中持续形成情景与语义长期记忆
论文阅读·人工智能·学习·开源·github
xiami_world1 小时前
Xmind、Miro、博思白板AI怎么选?思维导图/流程图自动生成
人工智能·ai·信息可视化·流程图·xmind
wp123_11 小时前
圆盘拨动电位器机电转换原理,国内外产品性能与成本比拼
人工智能·科技·硬件工程
蜡台2 小时前
AI Agent 架构终极教程:从原理分层、四大范式到生产级落地实战
网络·人工智能·架构
乐维_lwops2 小时前
2026选择运维监控系统时应该重点考察哪些功能?
大数据·运维·人工智能
小新科研测评2 小时前
文献管理工具同步太麻烦?2026年4款多端同步工具实测,换设备不丢笔记
论文阅读·人工智能·笔记·ai·电脑