Python WebAcademy Blog

Pillow 13.0がリリース。重大な脆弱性を含む多数のセキュリティ修正と、読み込みの高速化を初心者向けに解説

|

Pythonの画像処理ライブラリPillowの13.0.0が公開されました。深刻度が最も高いCriticalを含む多数のセキュリティ修正が入り、Python 3.10のサポートを終えて3.15に正式対応しています。importにかかる時間の短縮や、パレット画像の色反転への対応など、実際に12.3.0と13.0.0を並べて動かした結果とともに整理します。

Pythonの画像処理ライブラリPillowの13.0.0が公開されました。PyPIの記録によると、日本時間では2026年10月17日の朝に配布が始まっています。

今回の目玉は、とても多くのセキュリティ修正です。公式のリリースノートには、深刻度が最も高いCriticalの問題が2件、次に高いHighの問題が13件も並んでいます。

画像を扱うアプリでPillowを使っている方は、できるだけ早く更新しておきたい版です。今回は、何が直ったのか、ほかに何が変わったのかを順番に見ていきます。

まずは何が変わったのかを整理しよう

最初に、今回の変更を大きく分けて表にまとめます。内容は、Pillowの公式リポジトリにある13.0.0のリリースノートにもとづいています。

分類 主な中身
セキュリティ Criticalを含む多数の脆弱性を修正
Pythonの対応範囲 3.10のサポートを終了し、3.15に正式対応
速度 importにかかる時間が12.3.0のおよそ半分に
新機能 新しい縮小フィルター、パレット画像の色反転など
互換性のない変更 一部の古い機能の削除や、保存時の動きの変更

PyPIの記録によると、13.0.0が必要とするPythonは3.11以上です。3.10のままpip installすると、13.0.0ではなく、それより前の版が入ります。

Pillowそのものがまだよくわからない方は、先にこちらを読んでおくと話がつながります。【関連記事】PythonのPillowとは?

多数のセキュリティ修正が入った

リリースノートでは、修正された脆弱性が深刻度ごとに並べられています。それぞれの件数を数えると、次のようになりました。

深刻度 件数 主な例
Critical 2 画像の形式を変えたあとに古い領域が再利用される問題、JPEGの読み込みでのバッファオーバーフロー
High 13 TIFFやPDF、WMF/EMFの読み書きでの範囲外アクセスなど
Medium 20 圧縮爆弾の検出をすり抜ける問題、処理が終わらなくなる問題など
Low 3 GIFやEPSの圧縮爆弾の検出の不備など

件数は、リリースノートに箇条書きされた項目の数です。1つの項目に複数の識別番号がまとめられているものもあります。

画像ファイルは攻撃の入口になりやすい

画像を開くだけで危ないの?と思うかもしれません。けれども、画像の読み込みは、ファイルの中身を細かく解釈する、とても複雑な処理です。

わざと壊した画像を読み込ませて、メモリの範囲外を読み書きさせるのは、古くからある攻撃の手口です。利用者が画像をアップロードできるWebアプリでは、特に影響が大きくなります。

圧縮爆弾とは

リストに何度も出てくる圧縮爆弾、英語でdecompression bombとは、小さなファイルが展開すると膨大な大きさになる仕掛けのことです。読み込んだだけでメモリを使い果たし、サーバーを止めてしまうおそれがあります。

Pillowには、もともと大きすぎる画像を検出して止める仕組みがあります。今回は、seek()を使うなどしてその検出をすり抜けられる問題が、いくつもの形式で見つかり、まとめて直されました。

私は10年ほどエンジニアとして開発に関わってきましたが、画像のアップロード機能は、作るのは簡単でも守るのが難しい機能だと感じています。外から受け取ったファイルを扱うライブラリは、いちばん優先して更新するのが鉄則です。

ライブラリの脆弱性をまとめて調べるには、pip-auditが便利です。【関連記事】pip-auditとは?

Python 3.10のサポート終了と、3.15への正式対応

リリースノートによると、Pillowは13.0.0でPython 3.10のサポートを終えました。理由は、3.10が2026年10月にサポート期間を終えたためと説明されています。

一方で、Python 3.15には正式に対応しました。12.3.0の時点でも3.15のベータ版向けの配布物が用意されていて、正式版の公開と同時に使えるよう準備されていたそうです。

主要なライブラリが3.10を外していく流れは、先日の記事でもまとめました。Pillowもその流れに加わった形です。【関連記事】Python 3.10のサポート終了から2週間、主要ライブラリの対応状況

importが速くなった

13.0.0では、Pillowの読み込みにかかる時間が大きく縮みました。リリースノートには、12.3.0のおよそ半分の時間で読み込めるようになったと書かれています。

なぜ速くなったのか

リリースノートによると、PIL.Imageがloggingを読み込まなくなりました。また、一部の操作でしか使わないtempfileのようなモジュールは、初めて使うときに読み込むようになっています。

さらにPython 3.15では、__lazy_modules__という仕組みで、残りの標準ライブラリの読み込みも後回しにしています。これは、3.15で入ったlazy importの仕組みを使ったものです。

lazy importそのものについては、Python 3.15の記事で実際に動かしながら紹介しました。【関連記事】Python 3.15が正式リリース

手元で測ってみた

実際に、12.3.0と13.0.0を別々の仮想環境に入れ、from PIL import Imageにかかる時間を比べました。Pythonの-X importtimeという仕組みで、15回ずつ測った中央値です。

版 読み込みにかかった時間(中央値)
Pillow 12.3.0 約20.5ミリ秒
Pillow 13.0.0 約13.2ミリ秒

手元のPython 3.11では、およそ3分の1ほど短くなりました。リリースノートの半分という数字は、Apple製のMacで測ったものなので、環境によって差が出るのは自然です。

1回あたりはわずかな差ですが、コマンドラインのツールのように何度も起動するプログラムでは、積み重なって効いてきます。

画像の読み書きそのものも速くなった

リリースノートによると、macOSとLinux向けの配布物に同梱されたいくつかのライブラリが、これまで最適化なしでビルドされていました。13.0.0ではこれが直り、12.3.0と比べてJPEG 2000の読み込みは2〜3倍、文字の描画は最大3倍速くなったと説明されています。

Windows向けの配布物は、もともとこの問題の影響を受けていなかったそうです。

新機能を12.3.0と比べてみた

続いて、新しく加わった機能を試してみましょう。今回は、パレット画像の色反転と、新しい縮小フィルターの2つを確かめます。

パレット画像とは、使う色の一覧を持ち、各画素がその番号で色を表す形式のことです。GIF画像などでよく使われ、PillowではPモードと呼ばれます。

import PIL
from PIL import Image, ImageOps

print("Pillow", PIL.__version__)

# パレット(Pモード)の画像を作る
img = Image.new("RGB", (64, 64), (200, 30, 30)).convert("P")

try:
    inverted = ImageOps.invert(img)
    print("invert:", inverted.convert("RGB").getpixel((0, 0)))
except NotImplementedError as e:
    print("NotImplementedError:", e)

# 新しい縮小フィルター
filters = [name for name in ("MKS2013", "MKS2021") if hasattr(Image.Resampling, name)]
print("new filters:", filters)

まずは12.3.0で実行した結果です。

Pillow 12.3.0
NotImplementedError: mode P support coming soon
new filters: []

続いて13.0.0です。同じコードで、色の反転がうまくいき、新しいフィルターも見つかりました。

Pillow 13.0.0
invert: (51, 204, 204)
new filters: ['MKS2013', 'MKS2021']

12.3.0では、パレット画像の反転はまだ対応していないというエラーになりました。13.0.0では、赤っぽい色が反転して、青緑っぽい色に変わっています。

新しいMKS2013とMKS2021は、Magic Kernel Sharpと呼ばれる縮小フィルターです。resize()やthumbnail()で、ほかのフィルターと同じように指定できます。

今後削除される予定の機能

リリースノートには、将来取り除かれる予定の機能も書かれています。日付まで明記されているので、表にまとめておきます。

機能 削除の予定
JpegImageFile.load_djpeg Pillow 14(2027年10月15日)
IM形式の画像 Pillow 15.0.0(2028年10月15日)
ImageQt.align8to32() 非推奨。内部向けの関数のため代わりはなし

日付を見ると、Pillowは毎年10月にメジャーバージョンを上げる予定で動いているようです。次の大きな変更が来る時期を前もって知っておけるのは、使う側にとってありがたいことです。

load_djpegを使っている場合は、リリースノートのとおり、組み込みのJPEGデコーダーを使うか、djpegを直接呼んで結果をPillowで読む形に切り替えましょう。IM形式は使う人の少ない形式なので、多くの方には関係ないはずです。

自分の環境のPillowを確かめる

最後に、手元のPillowのバージョンを確かめておきましょう。ターミナルでpip show pillowと打つか、Pythonの中でimport PIL; print(PIL.__version__)と書けば表示されます。

13.0.0より前の版だった場合は、pip install --upgrade pillowで更新します。Python 3.10を使っている場合は13.0.0が入らないので、Python本体の更新もあわせて考えてください。

上げる前に確かめたいこと

13.0.0には、互換性のない変更もいくつか含まれています。リリースノートから、初心者にも関係しそうなものを表にまとめます。

変更 中身
Iモードの画像をPNGで保存 これまでは値を黙って切り詰めていたが、それをやめた。保存前に変換が必要
小さなICOの保存 16×16より小さい画像は、その大きさのまま保存されるように
get_child_images()の移動 ImageFileのメソッドへ移った
古い属性の削除 ExifTags.IFD.Makernoteなどを削除

リリースノートによると、32ビットのIモードの画像をPNGで保存するときは、im.convert("I;16").save("out.png")のように、先に変換するよう案内されています。

以前、画像の変換処理でライブラリを上げたら、エラーは出ないのに一部の画像だけ色が変わっていて、気づくまで時間がかかったことがあります。更新の前後で、代表的な画像を何枚か変換して見比べると安心です。

まとめ

Pillow 13.0.0が公開されました。Criticalを含む多数のセキュリティ修正が入り、Python 3.10のサポートを終えて3.15に正式対応し、importも速くなっています。

利用者から画像を受け取るアプリでPillowを使っている方は、できるだけ早く更新してください。そのうえで、互換性のない変更に当てはまる箇所がないかを確かめておきましょう。

ここまでお読みいただきありがとうございました。

参考情報

次のアクション

記事で学んだ内容を実際に動かしてみよう

Python WebAcademyでは、ブラウザ上でコードを書きながら基礎から実践まで体系的に学べます。

Python WebAcademyの学習画面

あわせて読む

関連記事

ブログ一覧へ

Python学習ロードマップ

まずはこの3講座から

記事で気になったテーマを、順番に手を動かしながら学べます。

ロードマップを見る