一个字段的差别,决定你的扫描器能不能告诉你升到哪
先看一条命令的输出。CVE-2026-16723 是 fastjson 1.x 上一条 CVSS 9.0 的 RCE:
bash
# 注意:git bash 下 gh api 路径不要加前导斜杠
gh api advisories/GHSA-crf3-v9rr-v7hj \
--jq '[.vulnerabilities[] | {range:.vulnerable_version_range, patched:.first_patched_version}]'
# [{"range":">= 1.2.68, <= 1.2.83","patched":null}]
受影响区间写得清清楚楚,first_patched_version 是 null。
再看同一条 advisory 在 OSV 侧的机器可读结构:
bash
curl -s https://api.osv.dev/v1/vulns/GHSA-crf3-v9rr-v7hj | python -c "
import sys, json
d = json.load(sys.stdin)
print(d['affected'][0]['ranges'])
"
# [{'type': 'ECOSYSTEM', 'events': [{'introduced': '1.2.68'}, {'last_affected': '1.2.83'}]}]
字段名是 last_affected ,不是 fixed。
这两个字段不是一回事
fixed: X------ 升到 X 就安全了last_affected: X------ X 是最后一个中招的,至于该升到哪,没说
差别听起来很细,落到代码里是这样的:
python
# 常见的区间判定写法
def hit(ver, intro, fixed):
if intro and ver < intro: return False
if fixed and ver >= fixed: return False
return True # ← fixed 是 None 时,永远走到这里
这段代码对 CVE-2026-16723 会把 1.2.84 判成中招 ------ 因为它只读 fixed, 而这条 advisory 的上界挂在 last_affected 上。
🔧 这不是我编的反例,是我自己的复核脚本。 写这篇文章之前我跑发文前复核,断言「1.2.84 不中 16723」当场 FAIL 。 查下去才发现字段读漏了。数据里答案是有的,只是不在我以为的那个字段上。
顺带,这条 advisory 的 versions 字段逐个列举了 21 个受影响版本 ,最高就是 1.2.83, 1.2.84 不在里面。判断依据是充分的,只是不在 fixed 那一栏。
NVD 侧是另一种缺法
bash
curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-16723" | python -c "
import sys, json
c = json.load(sys.stdin)['vulnerabilities'][0]['cve']
print(c['vulnStatus'], [m['cvssData']['baseScore'] for m in c['metrics']['cvssMetricV31']])
"
# Deferred [9.0]
有 9.0 的评分,没有 CPE 版本区间。 依赖 NVD 做版本匹配的工具,在这条上匹配不到东西。
⚠️ Deferred 是 NVD 近年积压的通用状态,不是针对这条 CVE ,我也只读到这一次 ------ 这里只陈述现象,不做因果推断。
佐证:把 fastjson 1.x 四条 advisory 摆在一条版本轴上
| CVE | 严重度 | 受影响区间 | 修复版 |
|---|---|---|---|
CVE-2017-18349 |
CRITICAL | <= 1.2.24 |
1.2.31 |
CVE-2025-70974 |
CRITICAL | < 1.2.48 |
1.2.48 |
CVE-2022-25845 |
HIGH 8.1 | >= 1.2.25, < 1.2.83 |
1.2.83 |
CVE-2026-16723 |
CRITICAL 9.0 | >= 1.2.68, <= 1.2.83 |
1.2.84(advisory 里没写) |
⭐ 注意中间那两行:CVE-2022-25845 的修复版 1.2.83,正好是 CVE-2026-16723 区间的上界。
为修 2022 那条升到 1.2.83 的人,一脚踩进 2026 这条里。 同时躲开两条的只有 1.2.84。
而 1.2.84 这个答案,恰恰是 first_patched_version 那一栏没写的那个。
边界
- 这四条里只有 16723 一条 的
first_patched_version是空的, 另外三条都有正常的fixed,扫描器对它们工作正常 ------ 别读成「fastjson 的洞扫描器全看不见」。 1.2.25那条下界 GitHub 与 NVD 写法不同(NVD 没给下界),本文不对 1.2.25 以下的版本下判断。