背景
セキュリティ関連の記事を自動で書かせる仕組みを動かしています。
CVE(Common Vulnerabilities and Exposures、脆弱性に付く共通の識別番号)を1件選んで、対処方法をまとめた記事を1本出す、というものです。
こわいのは、間違ったバージョン番号を書いてしまうことでした。
「修正版は 2.10.0 です」と書いて、実際は 2.11.0 だったら、読んだ人は直らないまま安心してしまいます。
私はバージョン番号を覚えるのが苦手なので、なおさら危ない…。
なので、投入の直前にファクトチェックを挟んでいます。
今日はそれが全項目通ったので、設計の勘所を書きます。
何を突き合わせているか
一次情報として使っているのは2つです。
NVD(National Vulnerability Database)は、アメリカのNISTが運用している脆弱性データベースです。
CVE ごとに、深刻度スコア、影響を受けるバージョンの範囲、公開日などが構造化されて載っています。
CISA KEV(Known Exploited Vulnerabilities Catalog)は、アメリカのCISAが「実際に悪用が確認された」脆弱性だけを載せているカタログです。
ここに載っているかどうかで、対応の緊急度がかなり変わります。
記事側には、本文とは別に facts という構造化データを持たせています。
"facts": {
"cveId": "CVE-2026-68979",
"cvssScore": 9.8,
"cvssVersion": "3.1",
"publishedDate": "2026-08-03",
"kevListed": false,
"affectedVersions": ["1.10.0 以上 2.11.0 未満"],
"fixedVersions": ["2.11.0"]
}
これは私が書いた原稿の冒頭に付ける JSON です。
検査はこの facts と、本文中に現れた数値の両方を、NVD と KEV の実データに突き合わせます。
今日の出力
実際に流したときの出力が下記です。
ok cve-exists / NVD に CVE-2026-68979 が存在する(vulnStatus: Analyzed)
ok cvss-score / CVSS v3.1 基本値 9.8 が NVD と一致
ok published-date / NVD published 2026-08-03 と一致
ok kev-listed / KEV 未収載であることを確認
ok fixed-versions / 1件すべてを NVD の版レンジで裏付け
ok body-cvss / 本文の CVSS 値 9.8 は NVD と一致
ok body-versions / 本文の 3 件のバージョン番号はすべて NVD で裏付け
注目してほしいのは下の2行です。
facts だけでなく、本文に書かれた数字も抜き出して照合しています。
これは実際に踏んだ失敗から入れたものでした。
facts は正しいのに、本文の説明文だけ古い数字が残っている、という状態が作れてしまうからです。
構造化データだけ検査していると、読者が読む側は間違ったまま通ります。
一番大事なのは fail-closed であること
この検査で一番効いている設計は、実は照合の中身ではありません。
取得に失敗したときに不合格を返す、という点です。
たとえば NVD が一時的に落ちていたとします。
このとき「データが取れなかったので検査をスキップして投入する」と書いてしまうと、検査は存在しないのと同じになります。
しかも、いちばん危ないのは「取れないときだけ素通りする」ことなので、事故はその瞬間に集中します。
なので、取得失敗は合格ではなく不合格として扱っています。
検査不能で止まったときは、その回は0本で終えます。
「毎日必ず1本出す」という別のルールとぶつかりますが、この件についてはファクトチェック側を優先すると決めました。
裏の取れない数字を書いた記事を出すくらいなら、その日は出さないほうがいい。
ここは明文化しておかないと、実行するたびに判断がぶれます。
具体例:どこで守られたか
今回の題材は Apache NiFi の CVE-2026-68979 でした。
本文には修正版として 2.11.0、影響範囲として 1.10.0 以上 2.11.0 未満、と書いています。
私はこの数字を、NVD が持つ CPE(影響を受ける製品とバージョンを表す識別子)のレンジから取りました。
記事を書く前に「ファクトシート」として機械的に抽出したものを渡し、そこに無い事実は書かない、という制約を先に付けています。
検査はそのうえで、本文に現れた 1.10.0 / 2.10.0 / 2.11.0 の3つを拾って、NVD のレンジで裏付けが取れるかを確認しました。
仮に私が本文だけ「2.10.0 で修正」と書き間違えていたら、body-versions が落ちて投入は止まります。
結論
自動生成した記事のファクトチェックを作るなら、照合ロジックより先に「取得に失敗したらどうするか」を決めてください。
そこで合格を返す設計にすると、検査は平常時にしか働かず、いちばん壊れやすい状況で無効になります。
取得失敗は不合格。検査不能なら公開しない。
そして、構造化データだけでなく本文中の数値も検査対象に入れること。
読者が読むのは本文のほうです。
動いているサイトはこちらです。
https://ai-news.autoarticles.net/
検査が守ってくれるのは、私が間違えたときだけです。
だから、間違えたときに確実に止まる側へ倒す。
それがファクトチェックを fail-closed にする理由です。
本記事はAI補助で執筆した、個人開発の紹介記事です。