CVEウォッチの脆弱性ページ自動生成(検証ガード・HowTo対応手順・関連CVE)

自作の「脆弱性対応ウォッチ」(cve.autoarticles.net)は、深刻度の高いCVEを日本語の実務目線でまとめる静的サイトだ。生成器は依存ゼロのNodeで、data/vulns.json から /cve/<id> ページを吐く。実務で使えるサイトにするための肝は、(1)載せるデータを厳しく検証する、(2)対応手順を HowTo として構造化する、(3)関連CVEを機械的に出す、の3点だ。

1. 検証ガードで「弱い/欠損データ」を弾く

このサイトが扱うのは High/Critical だけ。生成前に次を満たさないエントリはビルドから弾く。

  • severity が High/Critical 以外はNG。
  • cvssScore が 7.0 未満はNG。
  • source(一次情報URL)が必須。
  • cveId / title / summary が必須で、cveId の重複もNG。

「たくさん載せる」より「載せるものを正しく保つ」を優先している。捏造しないための一番の防波堤が、この入口のバリデーションだ。

2. remediation から HowTo を生成

各CVEの詳細ページには、確認できた対応手順だけを HowTo のステップとして出す。「アップデートする」を漠然と書くのではなく、確認済みのクラウド/OSごとの手順を順序立てて表示する。手順が確認できないものはステップにしない。

3. 関連CVEを機械的に出す

ベンダー・製品が一致する他のCVEを関連として並べる。IDでMapをつくればO(1)で引ける。読者が「同じ製品の他の穴」へ回遊でき、内部リンクも増える。詳細ページは Article+BreadcrumbList の構造化データを付ける。

実際に試す

依存ゼロで、検証ガード・HowTo生成・関連CVE算出の核をNodeで再現する。cve-build.js として保存し node cve-build.js(Node 18以上)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// cve-build.js — 検証ガード + HowTo + 関連CVE の最小再現(依存ゼロ)
const fs = require("fs");

const vulns = [
{ cveId: "CVE-2026-0001", vendorProject: "acme", product: "web", title: "acme web RCE",
summary: "認証前RCE", severity: "Critical", cvssScore: 9.8,
source: "https://example.com/advisory",
remediation: ["9.8.1 以上へ更新", "外部公開ポートを一時的に遮断"] },
{ cveId: "CVE-2026-0002", vendorProject: "acme", product: "web", title: "acme web XSS",
summary: "反射型XSS", severity: "Medium", cvssScore: 5.1, source: "" }, // 弾かれる
];

// --- 1. 検証ガード ---
function valid(v, seen) {
if (!["High", "Critical"].includes(v.severity)) return false;
if (!(v.cvssScore >= 7.0)) return false;
if (!v.source) return false;
if (!v.cveId || !v.title || !v.summary) return false;
if (seen.has(v.cveId)) return false;
seen.add(v.cveId);
return true;
}

// --- 3. 関連CVE(同一ベンダー/製品) ---
function relatedCves(v, all) {
return all.filter(
(o) => o.cveId !== v.cveId && o.vendorProject === v.vendorProject && o.product === v.product
);
}

const seen = new Set();
const passed = vulns.filter((v) => valid(v, seen));

fs.mkdirSync("public/cve", { recursive: true });
for (const v of passed) {
// --- 2. HowTo(確認できた remediation だけ) ---
const howto = {
"@context": "https://schema.org",
"@type": "HowTo",
name: `${v.cveId} の対応手順`,
step: (v.remediation || []).map((t, i) => ({
"@type": "HowToStep", position: i + 1, text: t,
})),
};
const article = {
"@context": "https://schema.org", "@type": "Article",
headline: `${v.cveId} ${v.title}`, url: `https://cve.autoarticles.net/cve/${v.cveId}`,
};
const rel = relatedCves(v, passed).map((r) => r.cveId).join(", ") || "なし";
const html = `<!DOCTYPE html><html lang="ja"><head><meta charset="utf-8">
<title>${v.cveId} ${v.title}</title>
<script type="application/ld+json">${JSON.stringify(article)}</script>
<script type="application/ld+json">${JSON.stringify(howto)}</script>
</head><body><h1>${v.cveId}</h1><p>CVSS ${v.cvssScore} / ${v.severity}</p>
<h2>対応手順</h2><ol>${(v.remediation||[]).map((t)=>`<li>${t}</li>`).join("")}</ol>
<p>関連CVE: ${rel}</p></body></html>`;
fs.writeFileSync(`public/cve/${v.cveId}.html`, html);
}
console.log("passed:", passed.map((v) => v.cveId));

期待される出力:

  • コンソールに passed: [ 'CVE-2026-0001' ] と出る(CVSS 5.1・source空の2件目はガードで除外)。
  • public/cve/CVE-2026-0001.html が生成され、HowTo の各ステップが <ol> と JSON-LD の両方に入る。
  • 関連CVEは同じ acme/web の他エントリがあれば列挙される(この例では通過が1件なので「なし」)。

実際の脆弱性ページと対応手順は 脆弱性対応ウォッチ で確認できる。

まとめ

  • 入口で厳しく検証し、弱い/欠損データはビルドから弾く。
  • 対応手順は確認できたものだけ HowTo にする。
  • 関連CVEはベンダー/製品一致で機械的に出し、回遊と内部リンクを増やす。

CVEウォッチの脆弱性ページ自動生成(検証ガード・HowTo対応手順・関連CVE)
https://blog.hashito.biz/2026/07/12/cve-watch-vuln-page-generation-howto-related/
著者
hashito
作成日
2026年7月12日
著作権