1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ServiceNow VR CVDBについて調べてみた

1
Last updated at Posted at 2026-06-18

はじめに

Vulnerability Response(VR)を使い込んでくると「自社の脆弱性スキャナーや内製ツールの情報をCVEレコードに直接反映したい」というニーズが出てきます。
そのとき気になるのが 「自前で登録した値は、後からNVDが走ったときに上書きされるのか?」 という点です。

本記事では実インスタンス(PDI)のテーブル定義とCVDUtilのスクリプトを直接確認した結果をもとに、この動作を解説します。


CVDB(Central Vulnerability Database)とは

CVDBはServiceNow Store配布のプラグイン(アプリ名: Central Vulnerability Database)です。
VRが依存するモジュールで、複数のセキュリティソース(NVD / CISA KEV / EPSS / Qualys / Wiz ほか)から投入されたCVEデータを 単一の統合CVEレコード に名寄せ・エンリッチします。

VRでいう「CVEレコード」の実体は sn_vul_nvd_entry テーブルです(CVDBが有効な環境でも変わりません)。


実機で確認したCVDB関連テーブル

sys_db_objectnameLIKEcvd で照会すると以下5テーブルが確認できます。

テーブル ラベル 役割
sn_sec_cvd_source_config Source configuration ソースレベル優先度の定義
sn_sec_cvd_source_field_priority Source field priority フィールド単位の優先度上書き
sn_sec_cvd_field_update_history Field update history フィールドごとの最終更新ソース記録(provenance)
sn_sec_cvd_m2m_entry_cvd Vulnerability CVD ソースレコード ↔ 統合CVEレコードのM2M
sn_vul_manual_ingestion_cvd_attributes Manual Ingestion CVD Attributes 手動投入ソースの生データ保持用

sn_sec_cvd_source_config の実レコードは次の2件でした。

ソース名 priority cvd_table
National Vulnerability Database Integration 10 sn_vul_nvd_entry
Manual Ingestion 1000 sn_vul_nvd_entry

数値が小さいほど優先度が高い。NVD(10)はManual Ingestion(1000)より強い。


優先度判定の実装 — CVDUtil._shouldUpdateField

CVDBへの書き込みはすべて Script Include sn_sec_cvd.CVDUtil(publicアクセス)を経由します。
フィールド更新可否を決めるコアロジックは _shouldUpdateField です(実機から抜粋)。

_shouldUpdateField: function(cvdGr, fieldName, incomingPriority, getLastPriorityFn, fieldSourcesMap) {
    // ① フィールドが空なら無条件で更新
    if (gs.nil(cvdGr[fieldName])) return true;

    var lastUpdateSource = fieldSourcesMap.hasOwnProperty(fieldName)
        ? fieldSourcesMap[fieldName]
        : this._getSource(cvdGr);

    // ② 前回の書き込み元が不明、または自分自身なら更新
    if (lastUpdateSource == "" || lastUpdateSource == this.source) return true;

    // ③ incoming の priority ≤ 前回書き込み元の priority のときだけ更新
    return incomingPriority <= getLastPriorityFn(lastUpdateSource);
}

判定の流れをまとめると次の通りです。

フィールドが空?
  → YES: 無条件で書く
  → NO:
       前回の書き込み元(sn_sec_cvd_field_update_history より)を特定
           前回書き込み元が不明 or 自分自身?
             → YES: 書く
             → NO: 自分の priority ≤ 前回書き込み元の priority?
                     → YES(同値含む): 上書き
                     → NO: スキップ(既存値を保持)

前回の書き込み元は sn_sec_cvd_field_update_history.field_sources(JSON)に記録されています。CVDUtilを通さず直接 sn_vul_nvd_entry に書くと、この履歴が残らないため優先度管理が完全に無効化されます。


自前Import SetでCVEを登録したあと、NVDに上書きされるか

シナリオ: 自前ソースを priority 500sn_sec_cvd_source_config に定義し、CVE-2026-XXXX を登録。その後、NVD連携(priority 10)が同一CVEを処理。

フィールド 状態 判定 結果
空フィールド ルール① NVDが埋める
自前が書いた値 最終更新元: 自前(500) ルール③: 10 ≤ 500 → true NVDが上書き

→ はい、NVDで上書きされます。
なお、自前ImportでCVDUtilを通さなかった場合も全フィールドがNVDに無条件で上書きされます。


自前の値をNVDから守りたい方法

方針A: フィールドレベル優先度で特定フィールドだけ守る(推奨)

sn_sec_cvd_source_field_priority に自ソース × 守りたいフィールドを登録し、priority を10未満にします(例: 5)。そのフィールドだけは自前が勝ち、他はNVDに任せられます。CVSSスコアはNVDに、社内のexploit情報は自前に、という使い分けが可能です。

方針B: ソースレベルでNVDより強い priority を設定する

sn_sec_cvd_source_config の priority を 10 未満(例: 1)にします。全フィールドで自前が勝ちますが、NVDによるエンリッチがほぼ効かなくなります。通常は非推奨。

方針C: ソース固有テーブルに切り出す(OOBのManual Ingestionの設計)

OOBの Manual Ingestion は priority 1000 でCVD本体では常にNVDに負ける設定ですが、modified severitysummary といった独自フィールドをソース専用テーブル sn_vul_manual_ingestion_cvd_attributes に保持します。CVD本体レコードで負けてもソース固有データは失われないため、「NVDには勝てないが独自情報も消えない」状態を維持できます。自前ソースでも同様に source_table を定義することで同じ設計にできます。


Import SetでCVDUtilを呼ぶコード例(変換マップ onComplete)

// onComplete Transform Script
(function runTransformScript(source, map, log, target) {

    // ソースとして登録した sn_sec_int_integration の sys_id を指定
    var integrationGr = new GlideRecord('sn_sec_int_integration');
    integrationGr.get('<自ソースのsys_id>');

    var util = new sn_sec_cvd.CVDUtil(integrationGr);

    // Import Set の各行を処理
    var row = new GlideRecord(import_set.getValue("table_name"));
    row.addQuery("sys_import_set", import_set.getUniqueValue());
    row.query();
    while (row.next()) {
        util.createOrUpdateCVDRecord({
            id: row.getValue("u_cve_id"),        // 必須。CVE ID
            summary: row.getValue("u_summary"),
            // cvss_score, exploit, cweList, referenceList, softwareList なども設定可
        });
    }

})(source, map, log, target);

createOrUpdateCVDRecordid(CVE ID)でコアレス判定を行うため、Transform MapにcoalesceフィールドマップやTarget Field設定は不要です。


まとめ

確認事項 答え
自前Import SetのCVEはNVDで上書きされるか される(NVD priority 10 < 自前 priority 500 のため) CVDUtilを通さなかった場合も全フィールドがNVDに無条件で上書きされる
タイミング NVD連携の次回実行時(デルタ取り込み or フル取り込み)
防ぎ方 フィールドレベル優先度 or ソース固有テーブルへの切り出し
CVDUtilを通さず直接書いた場合 優先度管理・履歴が無効化される。非推奨

CVDBの優先度設計は「どのフィールドをどのソースに任せるか」を明示的に宣言するものです。自前ソースを追加する際は、NVDとの役割分担を sn_sec_cvd_source_config / sn_sec_cvd_source_field_priority で意図的に設計することをお勧めします。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?