世界中のWebサイトやアプリで使われるオープンソースのリレーショナルデータベースMariaDBに、USAGE ON *.*(=実質的に何の権限も持たない)だけの一般ユーザーが、既存の管理者アカウントを乗っ取ってDBA権限を奪えるアクセス制御の欠陥が公表された。MariaDBの課題番号はMDEV-40470で、GRANT PROXY構文の認可チェックにあるズレを突く。2026年7月20日にHackerOne経由で報告され、9月7日に開示レポート(#3876430)が公開された。
依存パッケージ・ミドルウェア経由の脅威も含めた、OSS/開発者向けセキュリティ全体の見取り図は、ピラー記事サプライチェーン攻撃とは|手口・防御ツール比較・npm 12の新機構まで実践解説で整理している。本記事の位置づけをつかむ足がかりになる。
- ・正体:`GRANT PROXY`構文で、認可チェックが「空の認証句」をすり抜ける一方、永続化処理はその後ろに書かれた認証情報を保存してしまうズレ。区分はアクセス制御の不備(Improper Access Control)。
- ・誰が影響を受けるか:`USAGE ON *.*` だけを持つ一般ユーザーでも、既存管理者アカウントのパスワードを書き換えてDBAに昇格できる。プロキシ機能を使っているかは無関係。
- ・深刻度:報告者申告でCVSS 8.8(High)、MariaDBのJiraでは優先度Blocker。本記事公開時点でCVE番号は未割当。
- ・影響バージョン:10.6 / 10.11 / 11.4 / 11.8 / 12.3 系(および13.0系)。修正版は10.6.28・10.11.19・11.4.13・11.8.9・12.3.3(13.0系は13.0.2で対応予定)。
- ・今すぐやること:サーバーで `SELECT VERSION();` を実行し、上記の修正版未満なら更新。後述の判定スクリプトで機械的に確認できる。
MDEV-40470とは|USAGE権限だけで管理者を乗っ取れるアクセス制御の欠陥
MDEV-40470は、MariaDBのGRANT PROXYステートメントに存在するアクセス制御の欠陥だ。通常、他人のアカウントのパスワード(認証情報)を変更するにはALTER USERやCREATE USERといった強い権限が必要で、MariaDBは変更前に専用の権限チェック(内部的にはcheck_alter_user())を通す。
そもそもGRANT PROXYは、あるユーザーが別のユーザーとして振る舞う「プロキシユーザー」機能のための構文だ。GRANT PROXY ON 'A'@'host' TO 'B'@'host'とすると、Bが認証後にAの権限で動けるようになる。認証方式の統一やアプリ層でのユーザー切り替えに使われる、それ自体は正当な機能である。問題は、この構文の被付与者側に認証句を書ける文法上の余地があり、そこを本来の用途とは別の目的に転用できてしまう点にあった。
MDEV-40470では、GRANT PROXYの被付与者(grantee)を指定する箇所に、「空の認証方式」と「実際に効く認証方式」を並べて渡すと、権限チェックが前者だけを見て「認証は指定されていない」と誤認する。その結果、本来必要なはずの権限チェックがスキップされ、後ろに書かれた実際の認証情報だけが管理者アカウントに保存されてしまう。攻撃者はその新しいパスワードで管理者としてログインし、既存のDBA権限をそのまま引き継げる。
重要なのは、この攻撃に必要な権限が驚くほど少ないことだ。報告によれば、攻撃者はALTER USERもCREATE USERも、mysqlスキーマへのアクセスも、既存のPROXY権限も必要としない。USAGE ON *.*(=ログインできるだけ)で足りる。成立条件は、乗っ取りたい管理者のuser@hostが実在し、かつ攻撃者の接続元がそのhost指定に一致することだけだ。
この「必要なもの/不要なもの」を整理すると、権限昇格系の脆弱性としては前提が非常に緩いことがわかる。
| 攻撃に必要なもの | 攻撃に不要なもの(=ハードルが低い理由) |
|---|---|
ログインできる一般アカウント(USAGE ON *.* で十分) |
ALTER USER / CREATE USER 権限 |
乗っ取り対象の管理者 user@host が実在すること |
mysql システムスキーマへのアクセス |
攻撃者の接続元が対象の host 指定に一致すること |
既存の PROXY 権限 |
| — | サーバー側でのプロキシユーザー機能の有効化・設定 |
対象のuser@host(例: 管理者が@'%'のように広いhostで作られている場合)ほど条件が満たされやすい点にも注意したい。管理者アカウントのhostを必要最小限に絞る一般的なハードニングは、この脆弱性の成立条件を狭める効果もある。
① 何が起きうるか:ログインできるだけの一般アカウントが、既知の管理者アカウントを乗っ取りDBA権限を奪う。② 何を確認すればよいか:稼働中のMariaDBが修正版(10.6.28 等)以上かどうか。③ 何をすればよいか:修正版への更新と、当面の緩和(低権限アカウントの棚卸し・監査ログでのGRANT PROXY監視)。本記事は攻撃の再現手順(PoC)は掲載しない。
なお、本記事では悪用に使う具体的なSQL文(ペイロード)や再現手順は掲載しない。読者にとって価値があるのは「自分が影響を受けているかの確認」と「対処」であり、以降はその2点に絞る。
時系列と協調的開示|報告から修正・開示までの流れ
セキュリティ脆弱性は「開示日」に初めて危険になるわけではない。MDEV-40470の場合、修正版は開示(9月7日)より約1か月前に出そろっていた。時系列を分解すると次のようになる。
HackerOneへ報告
報告者 kevin_mizu"] --> B["2026-07-21
修正コミット
MariaDB/server"] B --> C["2026-08-13〜24
各系列で修正版リリース
10.6.28 ほか"] C --> D["2026-09-07
開示レポート公開
HackerOne #3876430"]
修正コミット(dbd60d0ad8da)は報告の翌日(2026年7月21日)にMariaDBのソースツリーへ入っている。そこから各サポート系列の定期リリースに取り込まれ、最も早い10.6系は8月13日(10.6.28)、その他の系列は8月24日にリリースされた。開示レポートが公開されたのはさらにその後の9月7日だ。
この時間差が意味するのは、日頃からマイナーバージョンの更新に追随していた環境は、開示のニュースが出る前から既に安全だったということだ。逆に、更新を長期間止めている環境ほど、開示のタイミングに関わらず先に手を打つべきリスクを抱えていたことになる。
本件は、MariaDBが運用するHackerOneのバグバウンティ/脆弱性開示プログラム(MariaDB Server & Connectors - Access control bypass スコープ)へ、研究者 kevin_mizu 氏によって報告された。HackerOne上のステータスはResolved(解決済み)で、深刻度は報告者申告でCVSS 8.8(High)、脆弱性の区分はアクセス制御の不備(Improper Access Control)とされている。MariaDBのプログラムは金銭的な報奨金(bounty)を提供しない方針のため、本レポートにも報奨金額は記録されていない。
タイムラインで見たとおり、修正コミットは報告の翌日に入り、修正版は約1か月かけて各系列へ配布され、その後にレポートが一般公開された。これは「修正を先に配ってから詳細を開示する」協調的開示(coordinated disclosure)の典型的な流れだ。開示レポートには再現手順(PoC)が含まれるが、本記事はその再現手順・悪用に使う具体的なSQL文を一切転載しない。読者にとって本当に必要なのは「自分が影響を受けているか」と「どう直すか」であり、以降でその2点を扱う。
なお、CVSS 8.8はあくまで報告者による自己申告値であり、NVD等の第三者機関が付与した公式スコアではない。本記事公開時点でCVE番号も未割当のため、深刻度の評価は「報告者申告のCVSS 8.8」と「MariaDB Jiraでの優先度 Blocker」の2点を併記するに留める。
なぜ起きたのか|認可チェックと永続化処理のズレ
根本原因は、MariaDBが「認証句が指定されたかどうか」を判定するhas_auth()という関数の実装にあった。修正コミットdbd60d0ad8daの説明はこう述べている——「空のパスワードや空のプラグイン名は『認証が指定されなかった』という意味ではない。『空の認証が指定された』という意味だ」。
GRANT文には認証方式を複数連ねて書ける(IDENTIFIED VIA ... OR ...のような多段指定)。MariaDBはこれを連結リストとして保持するが、修正前のhas_auth()はリストの先頭ノードしか見ていなかった。そのため先頭が空だと「認証は指定されていない」と誤判定し、権限チェック(check_alter_user())を丸ごとスキップしていた。
一方、変更を実際にデータベースへ書き込む永続化処理(replace_user_table())は、リスト内のすべての認証ノードを走査して保存する。この非対称性——「チェックは先頭だけ・保存は全部」——が、権限チェックをすり抜けたまま実際の認証情報を管理者アカウントへ書き込む経路を生んだ。
修正は極めて小さい。sql/structs.hのhas_auth()が、認証情報の中身の長さを調べる条件から、認証ノードが存在するかどうかだけを見る形に変わった。あわせてsql/sql_yacc.yy側で、current_userに対して空の認証オブジェクトを自動生成していた1行が削除された。
// 修正前: 中身(plugin名・auth文字列・平文パスワード)が空なら false
return auth && (auth->plugin.length || auth->auth_str.length || auth->pwtext.length);
// 修正後: 認証ノードが存在すれば true(=空の認証も「指定された」と扱う)
return auth;
この変更により、GRANT PROXYに空の認証句が付いていてもhas_auth()がtrueを返し、権限チェックcheck_alter_user()が正しく実行されるようになった。回帰テスト(mysql-test/main/grant5.test)も同じコミットで追加されている。
この欠陥は、脆弱性のクラスとしては「入力の検証側と処理側で見ている範囲が食い違う」という古典的なパターンに属する。今回は認可を判定する側(先頭ノードだけを見る)と、状態を書き込む側(全ノードを保存する)の食い違いだった。パーサーやバリデータが「代表値」だけを見て可否を判断する一方、実処理は入力全体を消費する——この非対称は、SQLに限らずHTTPリクエストのパース、設定ファイルの検証、認証フローなど至るところで再発する。MariaDBの権限昇格につながった今回のケースは、その教科書的な一例と言える。だからこそ、対策は「この1文をブロックする」ことではなく、判定と処理が同じ入力を見るようにする根本修正に置かれた。
影響を受けるバージョンと修正版
MariaDBのJira(MDEV-40470)が示す影響系列と修正版は次のとおり。リリース日は各系列のリリースノートで確認した値を併記する。
| 系列 | 区分 | 影響 | 修正版 | 修正版のリリース日 |
|---|---|---|---|---|
| 10.6 | LTS | あり | 10.6.28 | 2026-08-13 |
| 10.11 | LTS | あり | 10.11.19 | 2026-08-24 |
| 11.4 | LTS | あり | 11.4.13 | 2026-08-24 |
| 11.8 | LTS | あり | 11.8.9 | 2026-08-24 |
| 12.3 | 短期 | あり | 12.3.3 | 2026-08-24 |
| 13.0 | 短期 | あり | 13.0.2(対応予定) | 本記事公開時点で未リリース |
報告者はMariaDB 12.3.2と、開発リポジトリの13.1.0ビルドで再現を確認したとしている。10.5以前などサポート終了(EOL)に近い・終了した系列は、そもそも修正版が提供されない可能性が高い。サポート中の系列へ移行したうえで修正版に上げるのが正攻法だ。
Debian・Ubuntu・RHEL系などのディストリビューションが提供するMariaDBパッケージは、上流のバージョン番号を上げずに修正だけを取り込む(バックポートする)ことがある。上流版数が「10.6.27」に見えても、ディストリのパッケージ版に修正が入っている場合があるため、パッケージ管理システムのchangelog(例:
apt changelog mariadb-server / rpm -q --changelog mariadb-server)でMDEV-40470相当の修正が入っているかを併せて確認するのが確実だ。
自分が影響を受けているかの確認方法
影響判定でまず押さえるべきは、確認すべきは「サーバー」のバージョンであってクライアントではないという点だ。mariadb --version(クライアント)が返すのは手元のCLIツールの版であって、接続先のMariaDBサーバーが修正済みかどうかを何も示さない。クライアントとサーバーが別バージョンで動く構成は珍しくないため、必ずサーバーに接続して次を実行する。
SELECT VERSION();
出力は 10.6.28-MariaDB-1:10.6.28+maria~ubu2204-log のように、先頭にバージョン番号が並ぶ。この番号を上の表の修正版と比べればよい。系列ごとに修正版が異なる(10.6系なら10.6.28、11.8系なら11.8.9…)ため、目視で間違えないよう、系列ごとの修正版と機械的に突き合わせる判定スクリプトを用意した。以下は読み取り専用で、対象システムへの攻撃行為は一切含まない。
#!/bin/sh
# MDEV-40470 影響判定: 稼働中バージョンが修正版以上かを判定する(読み取り専用)
# 使い方: sh check_mariadb.sh # ローカルの mariadb クライアントから自動取得
# sh check_mariadb.sh 12.3.2 # バージョン文字列を直接渡す
ver="$1"
if [ -z "$ver" ]; then
ver=$(mariadb -N -B -e 'SELECT VERSION();' 2>/dev/null | sed -E 's/-MariaDB.*//; s/^([0-9.]+).*/\1/')
fi
[ -z "$ver" ] && { echo "バージョンを取得できませんでした。引数で渡してください: sh $0 12.3.2"; exit 2; }
series=$(echo "$ver" | awk -F. '{print $1"."$2}')
case "$series" in
10.6) fix=10.6.28 ;;
10.11) fix=10.11.19 ;;
11.4) fix=11.4.13 ;;
11.8) fix=11.8.9 ;;
12.3) fix=12.3.3 ;;
13.0) fix=13.0.2 ;;
*) fix="" ;;
esac
if [ -z "$fix" ]; then
echo "判定不可: $ver(系列 $series)は MDEV-40470 の修正版が公表された系列に一致しません。"
echo "→ サポート中の系列(10.6 / 10.11 / 11.4 / 11.8 / 12.3 / 13.0)の修正版へ移行してください。"
exit 3
fi
# sort -V で最小版を求め、現行が修正版未満かを判定
lowest=$(printf '%s\n%s\n' "$ver" "$fix" | sort -V | head -n1)
if [ "$ver" = "$fix" ] || [ "$lowest" = "$fix" ]; then
echo "OK: $ver は修正版 $fix 以上です(MDEV-40470 は修正済み)。"
exit 0
else
echo "要対応: $ver は脆弱です。系列 $series の修正版 $fix 以上へ更新してください。"
exit 1
fi
このスクリプトは、SELECT VERSION() の生出力(10.6.28-MariaDB-1:10.6.28+maria~ubu2204-log のようなディストリ固有のサフィックス付き文字列)でも先頭のバージョン番号を取り出して判定する。実行結果の例は次のとおり。
| 入力バージョン | 判定 | 終了コード |
|---|---|---|
| 12.3.2 | 要対応(脆弱) | 1 |
| 12.3.3 | OK(修正済み) | 0 |
| 10.6.27 | 要対応(脆弱) | 1 |
| 10.6.28 | OK(修正済み) | 0 |
| 11.8.8 | 要対応(脆弱) | 1 |
| 10.5.29 | 判定不可(対象外の系列) | 3 |
前述のとおり、ディストリのバックポートがある場合は版数だけでは判定しきれない。「要対応」と出た場合は、パッケージのchangelogでMDEV-40470相当の修正が入っていないかを最終確認してから対応方針を決めるとよい。
今すぐ取るべき対処
対処は「恒久対策」と「更新できない場合の緩和」に分けて考える。
・恒久対策:修正版へ更新する
最優先は、稼働中の系列の修正版(10.6.28 / 10.11.19 / 11.4.13 / 11.8.9 / 12.3.3、13.0系は13.0.2)以上へ更新することだ。単一系列内のマイナー更新(例: 10.11.x → 10.11.19)であれば互換性の問題は通常起きない。レプリケーション構成では、ノードを1台ずつ外して更新・再参加させるローリングアップグレードで無停止更新できる。
・緩和①:低権限アカウントの棚卸し
攻撃の起点は「ログインできる低権限アカウント」だ。アプリ用・開発者用・BIツール用などのアカウントを棚卸しし、不要なものを削除、host指定を必要最小限(特定IP・特定サブネット)に絞る。最小権限の原則を徹底するほど、起点となるアカウントは減る。
・緩和②:監査ログでGRANT PROXYを監視
server_auditプラグインやDBファイアウォール製品で、低権限アカウントが発行するGRANT PROXY文を検知対象にする。通常運用でGRANT PROXYをほとんど使わない環境なら、GRANT PROXY文の発行元アカウントをアラート条件にすると誤検知を抑えて異常を捕まえられる。
・緩和③:疑いがあればパスワードをローテーション
脆弱なバージョンを長期間稼働させていて、その間に低権限アカウントを多数配布していた場合は、念のため管理者を含む全アカウントのパスワードをローテーションしておくのが安全側の対応だ。
これらの緩和はあくまで時間稼ぎであり、根本対策は修正版への更新である点は変わらない。
過去のMariaDBセキュリティ事案との関係
MariaDBでは2026年に入ってから、性質の異なるセキュリティ事案が続いている。今回のMDEV-40470は「認証済みの低権限ユーザーによる権限昇格」だが、同じMariaDBでも攻撃面はまったく別だ。2026年6月には、クラスタ機能Galera(wsrep)まわりのパラメータインジェクションによるリモートコード実行(CVSS 10.0)が公表されている。こちらの詳細はMariaDB CVE-2026-49261|wsrep_notify_cmd 経由のRCEと修正版・影響確認で解説している。
両者に共通するのは、「本来は内側で守られているはずの境界(権限体系・クラスタ通信)が、想定外の入力経路で崩される」という構図だ。単一のCVEやMDEVを個別に潰すだけでなく、バージョン追随を運用に組み込み、低権限アカウントの棚卸しと監査ログを常態化することが、この種の事案への最も効く備えになる。開発言語やORMをまたいだSQL層の脆弱性という観点では、Node.js ORMのSequelize CVE-2026-69240|Oracle方言のSQLインジェクションの再発パターンも参考になる。
まとめ
MDEV-40470は、USAGE ON *.*だけの一般ユーザーがGRANT PROXY構文のズレを突いて既存管理者アカウントを乗っ取れる、影響の大きいアクセス制御の欠陥だ。原因は「権限チェックは認証句の先頭だけを見る・永続化は全ノードを保存する」という非対称性にあり、修正はhas_auth()を「中身の有無」から「存在そのもの」で判定する形へ変えた小さな差分で行われた。
読者がやるべきことは明快だ——サーバーでSELECT VERSION()を実行し、系列ごとの修正版(10.6.28 / 10.11.19 / 11.4.13 / 11.8.9 / 12.3.3、13.0系は13.0.2)以上かを確認する。未満なら更新し、当面は低権限アカウントの棚卸しと監査ログでのGRANT PROXY監視で守りを固める。修正版は開示より前の2026年8月に出そろっているため、更新のハードルは高くない。
参照ソース
- HackerOne #3876430 — MariaDB GRANT PROXY permits unauthorized authentication changes and administrator account takeover(開示レポート・一次情報)
- MariaDB Jira MDEV-40470 — GRANT PROXY with empty password incorrectly checks grantor’s privileges(公式課題・影響系列と修正版)
- MariaDB/server commit dbd60d0ad8da — MDEV-40470 の修正(修正差分)
- MariaDB 10.6.28 Release Notes / 12.3.3 Release Notes(リリース日・修正内容)