背景
私は脆弱性情報をまとめるサイトを個人で運用しています。この記事で扱う CVE の個別ページもあります。
昨日(2026-10-02)、問い合わせ管理ツール Zammad の CVE が2件まとめて KEV に載りました。
自分で Zammad を立てたことはないのですが、OSS のヘルプデスクとして社内に置いている所は多い気がします。
版範囲を眺めていたら出典ごとに少しずつ違っていて、機械で判定すると取りこぼす版があったので、手を動かして確かめておきます。
2件の CVE は何か
CVE は、公開された脆弱性に振られる世界共通の識別番号だ。
KEV は、アメリカの CISA が「実際に悪用されている」と確認した脆弱性の一覧です。
今回の2件は 2026-10-02 に KEV へ収載され、米連邦機関向けの是正期限は 2026-10-05 になっています。
1件目の CVE-2026-102489 は、セッション固定(CWE-384)の脆弱性である。
セッション固定というのは、攻撃者が用意したセッションを利用者に使わせて、ログイン後のセッションを乗っ取る攻撃のことです。
これが、Zammad の実行ユーザー(zammad)権限でのリモートコード実行につながる。
2件目の CVE-2026-102490 は、権限管理の不備(CWE-269)で、ローカルの zammad ユーザーが root に昇格できる。
KEV の説明には、この2件は連鎖させられると書かれています。
つまり1件目で zammad ユーザーとして入り、2件目で root まで上がる、という組み合わせです。
NVD は、アメリカの NIST が運営する脆弱性データベースです。
NVD の評価は2件とも CVSS 3.1 で 9.8 になっている。
CVSS は脆弱性の深刻度を 0〜10 で表す指標で、9.0 以上が Critical です。
一次情報は下記です。
https://nvd.nist.gov/vuln/detail/CVE-2026-102489
https://nvd.nist.gov/vuln/detail/CVE-2026-102490
https://csirt.divd.nl/cases/DIVD-2026-00015/
https://community.zammad.org/t/take-care-local-privilege-escalation-cve-2026-102490-is-reported-as-being-actively-exploited/21297
DIVD はオランダの脆弱性調査の非営利団体で、今回の発見者です。
DIVD の記載によると、2026-09-21 に自分たちの Zammad がこの穴で侵害され、2026-09-24 に Zammad へ報告しています。
版範囲が出典ごとに違う
CVE-2026-102489 の版範囲は、私が読んだ範囲で3通りの書き方がありました。
- NVD の説明文と DIVD: 6.3.0 から 6.5.4 が該当。7.0.0 から 7.1.3 にも存在するが、環境の条件で悪用できない
- NVD の CPE: 6.3.0 以上 6.5.4 未満、と 7.0.0 以上 7.1.3 以下
- Zammad の声明: 悪用できるのは 6.5 以前で、7.0 以降は影響を受けない
CPE は、製品と版を機械で照合するための NVD の書式だ。
NVD の API から CPE を引いて「該当/非該当」を出す、という作りの判定は多いと思います。
気になったのは2つ目の「6.5.4 未満」です。
GitHub のタグを見ると、6.5 系の最後の版は 6.5.4 でした。
説明文は「6.5.4 まで」なのに、CPE は 6.5.4 を含まない。
この食い違いのせいで、6.5 系を最後まで上げて止めている環境ほど、CPE だけの判定では非該当に落ちます。
CVE-2026-102490 のほうは、NVD の CPE が「1.5.0 以上 7.1.0 未満」と「7.1.0-alpha」で、Zammad の声明の「1.5 から 7.1.0-alpha」と一致しています。
ただ Zammad の声明は、対策として 7.2.0 への更新を勧めています。
版ごとに並べて確かめる
文字で読んでいると端の扱いを取り違えそうだったので、出典ごとの範囲をそのままコードにして、版を当ててみました。
入力は Zammad の版の文字列(6.5.4 や 7.1.0-alpha の形)です。
自分の環境の版は、管理画面かパッケージ管理の表示で確かめた値を入れる想定です。
alpha は同じ番号の正式版より前に並べています。
// Zammad の版を、出典ごとの「影響範囲」に当てて比べる
function parse(v) {
const m = /^(\d+)\.(\d+)\.(\d+)(-alpha)?$/.exec(v);
if (!m) throw new Error('形式が違います: ' + v);
// alpha は同じ番号の正式版より前に並べる
return [Number(m[1]), Number(m[2]), Number(m[3]), m[4] ? 0 : 1];
}
function cmp(a, b) {
const x = parse(a), y = parse(b);
for (let i = 0; i < 4; i++) if (x[i] !== y[i]) return x[i] - y[i];
return 0;
}
const between = (v, lo, hi, hiInclusive) =>
cmp(v, lo) >= 0 && (hiInclusive ? cmp(v, hi) <= 0 : cmp(v, hi) < 0);
// CVE-2026-102489(セッション乗っ取り → zammad ユーザーで RCE)
const rce = {
// NVD の CPE: 6.3.0 以上 6.5.4 未満 / 7.0.0 以上 7.1.3 以下
nvdCpe: (v) => between(v, '6.3.0', '6.5.4', false) || between(v, '7.0.0', '7.1.3', true),
// NVD・DIVD の説明文: 6.3.0 to 6.5.4 が悪用可能(7.0.0〜7.1.3 は「存在するが悪用不可」)
text: (v) => between(v, '6.3.0', '6.5.4', true),
// Zammad の声明: 悪用できるのは 6.5 以前、7.0 以降は影響なし
vendor: (v) => cmp(v, '7.0.0-alpha') < 0,
};
// CVE-2026-102490(zammad ユーザー → root)
const lpe = {
// NVD の CPE: 1.5.0 以上 7.1.0 未満 と 7.1.0-alpha
nvdCpe: (v) => between(v, '1.5.0', '7.1.0', false),
// Zammad の推奨は 7.2.0 への更新。ここでは 7.2.0 未満を更新対象として扱う
vendor: (v) => cmp(v, '7.2.0') < 0,
};
const mark = (b) => (b ? '該当' : '- ');
console.log('version | 102489 CPE 説明文 声明 | 102490 CPE 7.2.0未満');
for (const v of ['6.2.0', '6.5.3', '6.5.4', '7.0.3', '7.1.0-alpha', '7.1.3', '7.2.0']) {
console.log(
v.padEnd(12), '|', mark(rce.nvdCpe(v)), mark(rce.text(v)), mark(rce.vendor(v)),
'|', mark(lpe.nvdCpe(v)), mark(lpe.vendor(v)),
);
}
Node.js v24.11.1 で実行した結果は下記です。
$ node zammad.js
version | 102489 CPE 説明文 声明 | 102490 CPE 7.2.0未満
6.2.0 | - - 該当 | 該当 該当
6.5.3 | 該当 該当 該当 | 該当 該当
6.5.4 | - 該当 該当 | 該当 該当
7.0.3 | 該当 - - | 該当 該当
7.1.0-alpha | 該当 - - | 該当 該当
7.1.3 | 該当 - - | - 該当
7.2.0 | - - - | - -
6.5.4 の行で、CVE-2026-102489 が CPE だけ非該当になっているのがわかると思います。
逆に 7.0.3 や 7.1.3 は、CPE では該当なのに説明文と声明では「悪用できない」側です。
CPE は「コードが存在する」範囲を、説明文と声明は「悪用できる」範囲を書いている、と読むのがよさそうです。
6.2.0 の行が声明だけ該当なのは、声明が「6.5 以前」としか書いておらず、私のコードが下限を置いていないからです(6.3.0 未満が危ないという意味ではありません)。
7.1.3 の行も見ておきます。
CVE-2026-102490 は CPE だと 7.1.3 が非該当ですが、Zammad が勧めているのは 7.2.0 です。
7.1.x が直っているのかどうかは、私が読んだ一次情報からは読み取れませんでした。
どの範囲で判定するか
私は、CPE だけで判定せず、説明文とベンダーの修正版のうち広いほうを採ることにしました。
理由は、取りこぼしと誤検知の重さが釣り合っていないからです。
誤検知(直っている版を「要更新」と言う)の損は、更新の手間が1回増えるだけ。
取りこぼし(6.5.4 を「非該当」と言う)の損は、悪用が確認済みの穴を開けたまま放置することです。
この件は DIVD 自身が実際に侵害されていて、しかも2件を連鎖させると root まで届く。
なので Zammad では、7.2.0 未満はすべて更新対象として扱います。
もう1つ、DIVD はログから侵害の痕跡を探すスクリプトも公開しています。
収載より前から悪用されていた件なので、更新だけでなくログの確認もしたほうがいい気がします…。
NVD の CPE で機械判定している人は、範囲の端の版(今回なら 6.5.4)を説明文と見比べ、食い違ったら広いほうかベンダーの修正版を閾値にしてください。
本記事はAI補助で執筆した、個人開発の紹介記事です。