トップ/記事一覧/Dompdfに脆弱性6件 CVE-2026-59941、PHPで請求書PDFを作るなら3.1.6へ
dompdf-cve-cover-ja

Dompdfに脆弱性6件 CVE-2026-59941、PHPで請求書PDFを作るなら3.1.6へ

PHPで請求書や帳票のPDFを作るときに広く使われている部品「Dompdf」に、6件の欠陥が公表されました。サーバー上のファイルを外から覗かれる恐れと、たった58バイトの画像1枚でPDF作成が止まる恐れがあります。修正版は3.1.6です。自分が使っているかを確かめる手順もまとめました。

ニュース2026年7月29日公開 本日更新
目次
この記事のポイント

PHPで請求書や帳票のPDFを作るときに広く使われている部品「Dompdf」に、6件の欠陥が公表されました。サーバー上のファイルを外から覗かれる恐れと、たった58バイトの画像1枚でPDF作成が止まる恐れがあります。修正版は3.1.6です。自分が使っているかを確かめる手順もまとめました。

PHPでHTMLをPDFに変換するライブラリ「Dompdf」に、6件の脆弱性がまとめて公表されました。米国立標準技術研究所のNVDに登録されたのは2026年7月28日20時17分〜21時17分(協定世界時)で、日本時間では29日の早朝にあたります。

影響を受けるのは 3.1.5 およびそれ以前のすべてのバージョン。修正版の Dompdf 3.1.6 は、CVE番号の公開より8日早い7月20日にすでに出ています。つまり直すものはもう用意されている状態です。

Dompdfは「自分が使っている自覚がないまま入っている」ことの多い部品です。そこを押さえておいてください。Packagist(PHPのライブラリ配布サイト)での累計ダウンロードは1億9,382万回、直近1か月で667万回。PHPで請求書・見積書・納品書・帳票のPDFを吐く仕組みを作ったなら、ほぼ確実に候補に挙がるライブラリです。WordPressのプラグイン経由で入っていることもあります。ですから、まず「自分の環境に入っているのか」を確かめる手順から書きます。

公表された6件の脆弱性の一覧

6件はすべて開発元のGitHub Security Advisory(GHSA、GitHubが運営する脆弱性の公式告知の仕組み)として7月22日に公開され、その6日後にCVE番号としてNVDへ流れてきました。NVDの評価者(NIST)による深刻度スコアは、この記事を書いている2026年7月29日時点でまだ付いていません(6件すべて審査待ちの「Received」状態)。下の表の数値は、開発元がGHSAに自分で付けたCVSS 4.0の自己評価です。

CVE番号内容CVSS 4.0
(GHSA自己評価)
分類(CWE)起きること
CVE-2026-55554読み取り許可フォルダの
境界チェック回避
2.3(Low)CWE-20 / CWE-22許可外のファイルを読まれる
CVE-2026-55555フォント指定を使った
ファイル存在の推定
2.3(Low)CWE-203どのファイルがあるか当てられる
CVE-2026-56722SVG画像に埋め込んだ
ファイルパスの読み出し
6.3(Medium)CWE-20 / CWE-22初期設定のまま画像ファイルを読まれる
CVE-2026-59941BMP画像の宣言サイズを
信じて確保する
6.3(Medium)CWE-40058バイトの画像でメモリを食い潰される
CVE-2026-59942巨大な画像1つで
PHPが落ちる
6.3(Medium)CWE-400 / CWE-770PDF生成が止まりサイトが応答しなくなる
CVE-2026-59943SVG内の画像参照で
ファイル・フォルダの存在が漏れる
6.3(Medium)CWE-209サーバー内の構造を探られる

この表を作るときに気づいた食い違いを2つ書いておきます。1つ目は深刻度の表記です。開発元の3.1.6のリリースノートは6件すべてを「Moderate(中)」と書いていますが、GitHubの脆弱性データベースが機械的に返す深刻度では、CVE-2026-55554とCVE-2026-55555の2件は「Low(低)」です。数値でいうと2.3で、6.3の4件とは扱いが違います。2つ目はバージョン表記です。これは次の節で書きます。

フォームを叩いて回る相手が探しているもの

この6件を実際に使う相手は、国家が背景にある高度な集団ではありません。お問い合わせフォームや見積依頼フォームを手当たり次第に叩いて、返ってくる反応の違いだけを見ている自動巡回の攻撃者です。PDFのダウンロードボタンがあるページ、入力内容を確認用PDFにして返す画面、そういう「ユーザーが打った文字がPDFに載る」入口を機械的に探しています。技術的な難易度が低く、認証も要らないため、標的を選ぶ必要がないのがこの手の穴の特徴です。

見積書のPDFを返す入口を見つけた相手のやり口は、2通りに分かれます。ひとつは、PDFに変換される文章の中へ細工した画像やフォントの指定を混ぜ込み、サーバーの中にどんなファイルが置かれているかを1件ずつ言い当てていく探索。設定ファイルや鍵の置き場所が特定できれば、次の攻撃の下準備になります。もうひとつは、たった数十バイトの画像を送り込んでPDF生成の処理にメモリを使い切らせ、サイト全体を応答不能にする妨害です。

「注文確認のPDFが出てこない」「見積書がダウンロードできない」――サービスを使う側の目には、そう映ります。運営する側から見ると、まずPHPのプロセスが落ちてサイトが重くなり、深刻な場合はサーバー上の設定ファイルの位置や存在を外部に把握された状態になります。今回の6件に「サーバーを乗っ取られる」ものは含まれていませんが、乗っ取りの前段にあたる偵察には十分使えます。だからこそ、次に書く「自分が使っているか」の確認が最初の一手になります。

自分のシステムにDompdfが入っているか確かめる方法

Dompdfは単体で使うより、他の何かの部品として入っていることが多いライブラリです。実際、Packagistでこのライブラリを直接必要としているパッケージは741件、GitHubのスター数は11,159です。「PDFを作る機能を入れた覚えはあるが、中身がDompdfかは知らない」という状態がふつうに起こります。確認は次の順でやると早いです。

1. composerが使えるなら、まずこの1行

PHPのプロジェクトの根っこ(composer.jsonがある場所)で次を実行します。

composer show dompdf/dompdf

入っていればバージョンや説明が表示されます。入っていなければ何も見つからないという結果になります。

「入っているのは分かったが、誰が持ち込んだのか」を知りたいときは composer why dompdf/dompdf を使います(composer depends の別名です)。どのパッケージがDompdfを要求しているかが一覧で出るので、「laravel-dompdf経由だった」「帳票プラグインが持ち込んでいた」といった経路がはっきりします。

2. 脆弱性の有無をまとめて機械判定する

Composer 2.4以降には、インストール済みのパッケージを脆弱性データベースと突き合わせるコマンドが標準で入っています。

composer audit

今回の6件はいずれもPackagistの脆弱性データベースに「3.1.6未満が該当」として登録済みなので、3.1.5以下を使っていればここで6行まとめて出てきます。

この「依存関係を機械的に突き合わせる」考え方そのものについては、OSS サプライチェーン スキャナーで仕組みと限界を整理しています。今回のように「本体を直接入れた覚えがない部品」で穴が出たときに効くのは、結局この仕組みだけです。

3. composerが使えないサーバーでの確認

本番サーバーにcomposerを置いていない構成もよくあります。その場合はファイルを直接見ます。Dompdfはバージョン番号を書いたテキストファイルを同梱しているので、これが一番確実です。

cat vendor/dompdf/dompdf/VERSION

grep -A2 '"name": "dompdf/dompdf"' composer.lock

前者は 3.1.5 のようにバージョンがそのまま出ます。後者はcomposer.lockに記録された固定バージョンを確認する方法です。

4. WordPressの場合は場所が読めないので探索する

WordPressのプラグインは、名前の衝突を避けるためにライブラリの置き場所や名前空間を書き換えて同梱することがあります。そのため vendor/dompdf/ を見ても見つかりません。プラグインのフォルダごと探すのが確実です。

find wp-content -type d -name dompdf

find wp-content -name VERSION -path '*dompdf*' -exec cat {} +

1行目で同梱場所を洗い出し、2行目でそれぞれのバージョンを一気に表示します。

実例を1つ挙げます。WordPress公式ディレクトリで有効インストール数30万件の「PDF Invoices & Packing Slips for WooCommerce」は、Dompdfを同梱しています。最新版5.15.2の配布ファイルを当サイトで展開して確認したところ、同梱されていた場所は vendor/strauss/dompdf/dompdf/ で、VERSIONファイルの中身は 3.1.5 でした。このプラグインの公開日は7月13日、Dompdf 3.1.6の公開は7月20日ですから、順番として当然の結果です。プラグイン側の対応を待つ必要がある構成だ、という意味でもあります。WordPress本体側の更新事情についてはWordPress本体の脆弱性まとめも併せて確認してください。

危ないかどうかを分ける唯一の条件

6件の説明文を並べて読むと、全部が同じ前提の上に立っています。「攻撃者が、PDFに変換されるHTMLの中身を制御できるか」です。NVDの記述もそれぞれ「HTMLの入力を制御できる攻撃者は」「制限のないコンテンツを描画対象として渡せる場合」と書いています。つまり、条件がそろわなければ成立しません。

ここは冷静に線を引く価値があります。サーバー側で用意した固定のテンプレートに、データベースから取り出した値をエスケープして差し込むだけの帳票なら、今回の6件で狙われる余地はほとんどありません。逆に、お問い合わせ内容をそのままPDFにして返す画面、ユーザーが書式やスタイルを指定できる帳票、外部から受け取ったHTMLをPDF化するAPIを持っているなら、そこが入口です。

Dompdfのバージョン変換するHTMLの出どころ今回の6件の影響対応の優先度
3.1.6 以上どれでも6件すべて対象外対応不要
(設定の見直しのみ推奨)
3.1.5 以下ユーザー入力を
そのまま含む
6件すべて成立し得る最優先
(即更新)
3.1.5 以下外部から受け取った
HTMLやURL
6件すべて成立し得る最優先
(即更新)
3.1.5 以下固定テンプレート+
エスケープ済みの値のみ
成立条件を満たさない通常
(次の定期更新で)
3.1.5 以下管理者しか触れない
社内向け画面
外部からは成立しにくい通常
(次の定期更新で)
2.x 以下どれでも今回の6件+過去の重大な穴最優先
(3系へ移行)

最後の行だけ補足します。今回の修正は3.1.6でしか提供されておらず、2系への後方移植版は出ていません。Dompdf 2系には、2022年のCVE-2022-28368(任意コード実行、9.8)や2023年のCVE-2023-23924とCVE-2023-24813(いずれも10.0)といった、今回の6件よりはるかに重いものが残っています。2系を使っている場合は今回の話とは別に対応が必要です。

もう1点、成立条件に関わる細かい違いがあります。CVE-2026-55554とCVE-2026-55555の2件は、CVSSのベクタで「利用者の受動的な操作(UI:P)」が必要とされています。攻撃者が細工したHTMLを置いておき、誰かがそれをPDF化する操作をするまで待つ形です。残る4件は利用者の操作を必要としません(UI:N)。深刻度が2.3と6.3で分かれているのはこの差が大きく効いています。「認証不要」と書かれていても、条件は一律ではないということです。

6件を性質で2つに分けて読む

6件並べても頭に入りません。「読まれる・のぞかれる」4件と「落とされる」2件に分けると整理できます。前者は情報が漏れる話、後者はサービスが止まる話です。

CVE-2026-55554: 読み取り許可フォルダの境界チェックが文字列の前方一致だった

Dompdfには「このフォルダ以下のファイルだけ読んでよい」という制限(chroot設定)があります。NVDの記述によると、この判定を行う validateLocalUri() は、パスを realpath() で正規化したあと、strpos() で「許可フォルダのパスが先頭に一致するか」だけを見ていました。

問題は、正規化すると末尾のスラッシュが落ちることです。許可フォルダを /var/www にしていると、この文字列は /var/www2/var/www-admin/var/www_backup の先頭にも一致してしまいます。隣に置いたバックアップ用ディレクトリが、そのまま読み取り可能圏内に入るわけです。修正コミットでは、比較前に末尾へ区切り文字を付け直し、完全一致か区切り文字込みの前方一致でのみ許可する形に変わりました。報告者はvxhexとsnoopysecurityの2名です。

CVE-2026-56722: SVGを2回処理する構造の穴で画像ファイルを読み出せる

6件のうち、実際の読み出しに一番近いのがこれです。NVDの説明によると、DompdfはSVGを2回処理し、2回目の処理では1回目と同じ保護がかかっていませんでした。描画時にSVGを別ライブラリのphp-svg-libへ渡すのですが、その際に外部参照を有効にした状態で渡します。php-svg-lib側はDompdfの許可フォルダ設定を知らず、phar:// という特定の書き方だけを弾いて、あとはパスもプロトコルも検証せずにファイルを読みます。結果として、初期設定のままでも外部の認証なしの攻撃者がサーバー上の画像ファイルを読めるとされています。

この構図には既視感があります。2024年2月に公開されたGHSA-97m3-52wr-xvv2も、「php-svg-libが返した値をDompdf側が検証せずに使う」という同じ形で、深刻度は10.0でした。こちらは影響が画像ファイルの読み出しどまりのため6.3ですが、境界の引き方が同じ場所で繰り返し破れているのは事実です。修正はデータURI内のSVGからのローカル参照を正しく解決する変更と、解決できない参照を含むSVGを拒否する変更の2本です。なお、この1件だけGHSAに報告者のクレジットが載っていません。

CVE-2026-55555: フォント指定の反応の違いからファイルの有無を当てる

CSSの @font-face(外部フォントを読み込む指定)で file:// を使ってローカルのファイルを何度も参照させると、Dompdfの挙動が「そのファイルが存在するかどうか」で変わります。存在するファイルは繰り返し処理されてやがてメモリ不足で落ち、存在しないファイルは早い段階で無視される。この差を観測窓として使えば、読み取り許可フォルダの制限に関係なく、サーバー上のファイルの有無を1件ずつ確かめられるという指摘です。

成立には条件が付きます。大きなデータを送れるリクエストで制限のないHTMLを渡せること、そしてDompdfのメモリ上限が使い切れる程度に低い設定であること。警告表示の設定($_dompdf_show_warnings)が有効だと、より簡単に到達するとされています。報告者はg4nkdです。修正はスタイルシートのURLを解決時に検証する形で入りました。

CVE-2026-59943: SVGに埋めた画像参照でファイルとフォルダの存在が漏れる

仕組みはCVE-2026-55555と似ていて、使う道具がフォント指定ではなくSVGです。データURIとして埋め込んだSVGの中に <image> 要素を置き、その hrefxlink:href で別のファイルを参照させます。NVDの記述では、存在しないファイル(例として file:///DOESNOTEXIST)を指定したときと、実在するファイルやフォルダを指定したときで、Dompdfの振る舞いが違うと説明されています。CWE分類はCWE-209(エラーメッセージによる情報漏洩)。中身までは読めなくとも、「その設定ファイルはある」「そのディレクトリはある」が分かるだけで、次の攻撃の精度は上がります。報告者はw4tchd0geです。

CVE-2026-59941: 58バイトのBMP画像でメモリを食い潰される

具体性では、この1件が頭ひとつ抜けています。DompdfはBMP画像を受け取ると、PDFに埋め込める形式へ変換します。NVDの記述によると、このときヘッダに書かれた縦横の宣言値だけを見て、幅×高さの上限を確認しないまま変換処理に進んでいました。

結果どうなるか。58バイトのBMPファイルで、ヘッダに「6000×6000ピクセル」と書いておくだけで受理されます。そのあとPHPの画像処理関数 imagecreatetruecolor($width, $height) が、宣言どおりのピクセル領域をまるごと確保しにいきます。58バイトの入力が、数百メガバイトの確保に化けるわけです。

報告者のriodrwnは、実測値まで載せています。169バイトのリクエスト1本で、Dompdfの描画処理が最大約412MBのメモリと約4.8秒のCPU時間を消費したとのこと。同じサイズの無害なリクエストが約34MBだったので、1リクエストあたり約12倍のメモリ増幅です。しかも、この細工したBMPは data:image/bmp;base64,… の形でHTMLに直接書き込めるため、ファイルのアップロードも外部サーバーへの取得も要りません。HTTPリクエスト1本にすべて収まります。この「入力が小さいのに処理が重い」構図は、Apache HTTP/2で見つかった小さなリクエストによるサービス停止と同じ性質のものです。

CVE-2026-59942: 画像1つでPHPプロセスを落とせる

こちらは巨大なサイズ(例として3万×3万ピクセル)の画像を1つ含むHTMLでPHPプロセスをクラッシュさせるものです。厄介なのは、Dompdfが画像サイズの検証を持っているのに、それを迂回できる点です。NVDの説明では、ランダムノイズのような圧縮の効かない画像をBase64で埋め込み、特定のCSSコンテナで包むことで検証をすり抜けると書かれています。

原因は検証の順番です。サイズの検証は処理の早い段階で行われるのに、描画段階で行う「その物体の外接矩形の計算」や内部バッファの確保では、検証を通過した単一の物体に対するCPU時間やメモリ量の累積を厳しく制限していませんでした。認証のない外部の攻撃者が細工したHTML文字列を送るだけで、Webサーバーを完全に応答不能にできるとされています。報告者はfar00t01です。CWE分類はCWE-400とCWE-770の2つ。

なお、この2件はいずれもPHPの画像処理(GD拡張)を経由する経路です。Dompdfのcomposer.jsonではGD拡張は「画像の処理に必要」という推奨扱いですが、画像を含むPDFを作っている環境ならまず入っています。

修正版は3.1.6。ただし告知の「3.15」「3.16」は要注意

この6件で読み違えが起きやすいのは、バージョン番号の表記です。6件のNVD記述はすべて「versions 3.15 and prior(3.15およびそれ以前)」「fixed in version 3.16(3.16で修正)」と書いています。ところが、機械が読む部分と実際の配布物はこうです。

確認先影響範囲の表記修正版の表記
NVD・GHSAの説明文3.15 およびそれ以前3.16
GHSAの機械可読データ< 3.1.63.1.6
Packagistの脆弱性DB< 3.1.63.1.6
GitHubのタグ・リリースv3.1.5
(2026年3月3日公開)
v3.1.6
(2026年7月20日公開)
同梱のVERSIONファイル3.1.53.1.6

つまり「3.15」は「3.1.5」、「3.16」は「3.1.6」の書き間違いです。Dompdfに3.15や3.16というバージョンは存在しません。タグ一覧を見ればv3.1.6が最新で、その前はv3.1.5です。手元のバージョンが「3.1.4」だったときに「3.15より前だから対象外だ」と読んでしまうと逆になるので、判定は必ず「3.1.6以上かどうか」で行ってください。

更新の手順は依存関係の書き方によって変わりますが、Laravelでよく使われる barryvdh/laravel-dompdf(累計1億378万ダウンロード)は dompdf/dompdf: ^3.1 を要求しているだけなので、composer update dompdf/dompdf でラッパー側に手を入れずに3.1.6へ上げられます。

3.1.6で入った新しい上限設定と、無効になってしまう条件

修正の中身を見に行くと、DoS側の2件に対して新しい設定項目が追加されています。この挙動変化は更新前に知っておいたほうがいい内容なので、コミットを追って確認した結果を書きます。

画像のバイト数に上限を設けるコミットで、imageByteSizeLimit というオプションが増えました。画像を展開したときの推定メモリ使用量に上限を設け、超えたら描画せず警告を出す仕組みです。既定値は明示されておらず、Optionsクラスの初期化時にPHPの memory_limit の値がそのまま流し込まれます。

ここに落とし穴があります。設定値を受け取る setImageByteSizeLimit() は、0以下の値を渡されると内部的に「-1(上限なし)」として扱います。PHPの memory_limit は無制限を -1 で表すので、memory_limit = -1 の環境では、3.1.6に上げても画像サイズの上限が働きません。コマンドラインからPHPを実行する構成では既定でmemory_limitが無制限になっていることがあり、バッチで帳票を大量生成しているような環境は該当し得ます。3.1.6に上げたうえで、setImageByteSizeLimit('64M') のように明示的な値を入れるのが確実です。

逆方向の注意もあります。既定でmemory_limitと同じ値が上限になるため、これまで通っていた大きな画像が、更新後に描画されず警告だけ出るようになる可能性があります。更新後は、写真を大きく載せる帳票やロゴ画像の多いテンプレートが正しく出るかを一度確認してください。開発元はSecuring Dompdfのwikiで、利用者に設定を触らせないこと、入力を無害化すること、Dompdf本体を公開ディレクトリの外に置くことを推奨しています。

悪用の状況と、国内での扱い

現時点の外部指標を確認しました。

✓ 確認済みの事実

  • 6件すべて、NVDの評価者による深刻度スコアは未付与。状態は審査待ちの「Received」(NVD、2026年7月29日確認)
  • 実際に悪用されている脆弱性の米政府リスト(CISA KEV)には6件とも未掲載。カタログ版2026.07.27・全1,655件を確認
  • 攻撃が試みられる確率の推定値(EPSS)は6件とも未算出。FIRSTのAPIが該当0件を返す
  • CVE-2026-55555だけ、CISAによる評価記録(SSVC)がNVDに付いており、実証コードの状態が「PoC」、自動化の可否が「no」、技術的影響が「partial」と記録されている
  • JVN / JVN iPediaには登録なし。MyJVNのAPIで「dompdf」を検索して該当0件(2026年7月29日確認)。JPCERT/CCの注意喚起、IPAの呼びかけも見つかりませんでした
  • 日本語の解説記事・報道は確認できませんでした。開発元および報告者のX投稿も探しましたが、今回の6件に触れる投稿は見つかりませんでした

? まだ分からないこと

  • ?NVDの評価者がどの深刻度を付けるか ― GHSAの自己評価(2.3が2件、6.3が4件)から動く可能性があります
  • ?CVE-2026-55555以外の5件に実証コードがあるか ― CISAの評価記録が付いているのは1件だけです
  • ?Dompdfを同梱する各ライブラリ・プラグインが、いつ3.1.6を取り込むか

国内の登録も日本語記事も見つからないという状況は、逆に言えばこの6件について日本語で読める情報がまだほとんどないということです。KEVの掲載状況を継続的に追う仕組みについてはCISA KEV ダッシュボード(日本語版)にまとめてあります。

規模の話も正直に書きます。1億9千万ダウンロードのライブラリではありますが、今回の6件はいずれも「HTMLを攻撃者が制御できる」前提が必要で、しかも結果はファイルの読み出しかサービス停止までです。サーバーを乗っ取られる類のものではありません。ただし、条件に当てはまるサイト、つまりユーザーが打った文字がそのままPDFになる画面を持っているサイトにとっては、認証なしで、リクエスト1本で、確実に効く攻撃が手に入ったということです。PDF生成まわりで無認証の任意コード実行が出たWoo PDF Invoice Builderの事例と比べると重さは違いますが、影響条件の見極め方は同じです。

3.1.6へ上げ、上限設定を確かめる

まず composer show dompdf/dompdfcomposer audit を回して、Dompdfが入っているか、入っているならバージョンが3.1.6未満かを確定させます。WordPressなら find wp-content -type d -name dompdf です。ここで何も出なければ、今回の話は終わりです。

見つかった場合は、次に「そのPDFに載る文字はどこから来ているか」を確認します。データベースの値をエスケープして固定テンプレートに差し込むだけなら、緊急扱いにする必要はありません。次の定期更新のタイミングで3.1.6にすれば十分です。ユーザーの入力や外部から受け取ったHTMLが混ざるなら、composer update dompdf/dompdf を今日のうちに実行してください。

プラグイン経由で同梱されていて自分では上げられない場合は、プラグイン側の更新を待つことになります。その間の緩和策としては、外部リソースの取得を無効にする、読み取り許可フォルダを本当に必要な範囲まで絞る、PDF化するエンドポイントに送信サイズと回数の制限をかける、といった手が使えます。とくにDoS側の2件は「リクエスト1本で数百メガバイト」ですから、同時実行数の上限とタイムアウトを見直すだけでも効きます。

3.1.6に上げたあとは、大きな画像を含む帳票が今までどおり出るかを必ず1回確認してください。前述の imageByteSizeLimit が既定で有効になるため、挙動が変わる可能性があります。ここまでを1セットにして、依存ライブラリの棚卸しとして記録に残しておくと、次に同じことが起きたときの初動が短くなります。同じ発想の整理はApache Tomcatの脆弱性まとめでも扱っています。

Dompdfのように「PDFを作るライブラリがサーバー上のファイルを読める」性質そのものについては、GMOサイバーセキュリティ byイエラエによるサーバサイドPDF生成の脆弱性の解説が日本語で読める良い資料です。今回の6件に限らず、この分野の穴は同じ場所に繰り返し出ます。

参照元

avatar-m-1

堀川 慎

Backend Engineer / AWS / Django / Go