Django 5.2.16の脆弱性4件とは?RCE・SSRF・DoS・XSSの影響と5.2.17への更新方法

Django 5.2.16の脆弱性4件とは?RCE・SSRF・DoS・XSSの影響と5.2.17への更新方法
目次

Django 5.2.16の脆弱性4件とは?RCE・SSRF・DoS・XSSの影響と5.2.17への更新方法


初回確認:2026年8月5日
対象環境:Django 5.2.16 LTS
修正版:Django 5.2.17 LTS

2026年8月4日、Django Software Foundationは、4件のセキュリティ問題を修正したDjango 5.2.17とDjango 6.0.8を公開しました。

Django 5.2.16には、GeoDjangoを経由したサーバー側ファイル書込み・SSRF、メモリ消費型DoS、GeometryCollectionによるプロセスクラッシュ、Django Adminの格納型XSSが存在します。

Django公式は、Django 5.2.16の利用者に対してDjango 5.2.17への更新を推奨しています。Django 5.2.17では、Highが1件、Moderateが2件、Lowが1件修正されています。

なお、GBHackersの記事では「RCE、SSRF、DoS、XSSを実行できる」と報じられています。脆弱性の内容はDjango公式情報とおおむね一致していますが、RCEやSSRFはすべてのDjangoサイトで無条件に成立するものではありません。GeoDjango、GDAL、空間フィールド、管理画面の権限など、複数の成立条件があります。


この記事の要点

Django 5.2.16は4件のセキュリティ問題の影響を受けるためDjango 5.2.17へ更新する必要がある。

CVE-2026-15307はGeoDjangoの空間検索を通じてサーバー側ファイル書込みやSSRFを引き起こす可能性がある。

CVE-2026-15307のファイル書込みは環境と書込み先の条件がそろった場合にRCEへ発展する可能性がある。

CVE-2026-15337は長大な言語コードを大量に処理させることでDjangoワーカーのメモリを消費させる。

CVE-2026-15830は深く入れ子になったGeometryCollectionによってGEOSをクラッシュさせる可能性がある。

CVE-2026-15920は不正なURLField値をDjango Adminでクリックした管理者に格納型XSSを発生させる可能性がある。

GeoDjangoを利用していない環境でもCVE-2026-15337とCVE-2026-15920の確認は必要である。

Cloudflare WAFやIPSは脆弱性の悪用を軽減できるがDjango 5.2.17への更新の代わりにはならない。

Django 5.2 LTSは長期サポート版だが古いパッチバージョンが自動的に安全になるわけではない。


結論:Django 5.2.16から5.2.17へ更新する

現在Django 5.2.16 LTSを利用している場合は、Django 5.2.17 LTSへ更新してください

Django 5.2.17は、2026年8月4日に公開された同じ5.2系列のセキュリティパッチです。Django公式は、同一系列の最新パッチへ更新する質問に対する答えは常に「Yes」であると説明しています。

Django 5.2 LTSの延長サポートは2028年4月まで続きますが、サポートされるのはDjango 5.2系列の最新パッチです。古いDjango 5.2.16を使い続けることが保証されているわけではありません。

今回の対応優先度は次のとおりです。

優先度対応
最優先Django 5.2.16から5.2.17へ更新する
GeoDjango、PostGIS、GDALの使用状況を確認する
Django Adminに登録した空間フィールドの権限を確認する
外部入力を空間検索へ直接渡していないか確認する
set_language()の公開状況を確認する
URLFieldへ検証を通さず値を保存していないか確認する
Djangoコンテナの外向き通信とファイル書込み権限を制限する
継続WAF、IPS、EDRで悪用の兆候を監視する

関連記事

この記事は、次の記事の続報です。

関連記事:Django 5.2.15以前の脆弱性を解説|SQLインジェクション・キャッシュ漏えい・ASGI DoSの対策

関連記事では、2026年7月27日時点の修正版としてDjango 5.2.16を案内しています。しかし、2026年8月4日にDjango 5.2.17が公開されたため、現在の最低更新先はDjango 5.2.17へ変更されています

Django 5.2.16までに修正されたSQLインジェクション、共有キャッシュ、ASGI、メール、管理画面などの問題は関連記事を参照してください。今回の記事では、Django 5.2.16に残っていた4件へ焦点を当てます。


この記事で分かること

この記事では、次の内容が分かります。

  • Django 5.2.16で新たに修正対象となった4件の脆弱性

  • RCEやSSRFが成立する具体的な条件

  • GeoDjangoを使っていない環境への影響

  • 現在のDjango環境を確認する方法

  • Docker Compose環境でDjango 5.2.17へ更新する方法

  • 更新後に確認すべき管理画面、GIS、認証、WebSocketの動作

  • Cloudflare WAF、IPS、EDRで補助できる範囲

  • 同じ問題を見落とさないための再発防止策


対象読者・前提環境

この記事は、次の読者を対象としています。

  • Django 5.2を本番環境で運用しているエンジニア

  • Django Adminを業務管理画面として利用している担当者

  • GeoDjango、PostGIS、GDALを利用している担当者

  • Docker ComposeでDjangoを運用している担当者

  • Cloudflare、Nginx、Gunicorn、Uvicornを利用している担当者

  • Webアプリケーションの脆弱性対応を担当する人

想定する構成は次のとおりです。

Internet
   │
   ▼
Cloudflare
   │
   ▼
Nginx
   │
   ▼
Gunicorn + Uvicorn
   │
   ▼
Django 5.2.16
   ├─ PostgreSQL
   ├─ Redis
   ├─ Django Admin
   ├─ ファイルストレージ
   └─ GeoDjango/GDAL(使用時)

Djangoサービス名、PostgreSQLサービス名、ディレクトリ名は環境によって異なります。以降の例ではDjangoサービスをdjango、PostgreSQLサービスをpostgresとしています。


Django 5.2.16で何が起きたのか

Django 5.2.17では、Django 5.2.16に存在した次の4件が修正されました。

CVE内容Django評価主な影響
CVE-2026-15307空間検索によるファイル書込みとリクエスト送信Highファイル書込み、SSRF、条件付きRCE
CVE-2026-15337長大な言語コードによるキャッシュ消費Lowメモリ消費、DoS
CVE-2026-15830入れ子のGeometryCollectionModerateGEOSのクラッシュ、DoS
CVE-2026-15920AdminのURLField表示処理Moderate格納型XSS

全体像は次のとおりです。

Django 5.2.16
   │
   ├─ GeoDjangoの空間検索
   │    ├─ ファイルへ書込み
   │    └─ 外部・内部URLへ接続
   │
   ├─ 言語コードの確認
   │    └─ 長大な値をキャッシュしてメモリ消費
   │
   ├─ GEOSGeometry
   │    └─ 深い入れ子でプロセスをクラッシュ
   │
   └─ Django Admin
        └─ 不正なURLFieldをクリック可能なリンクとして表示

CVE-2026-15307:GeoDjangoのファイル書込み・SSRF・条件付きRCE

何が問題なのか

CVE-2026-15307は、今回修正された4件の中で最も深刻度が高い問題です。

GeoDjangoの空間検索では、ラスターを表す文字列や辞書がGDALRasterへ渡される場合がありました。

GDALは、地理情報や画像データをさまざまな形式で読み書きするためのライブラリです。たとえるなら、さまざまな地図や画像形式を開ける多機能な変換ソフトです。

正式には、GDALは地理空間データを読み書きするためのライブラリであり、ローカルファイルだけでなく、対応するドライバーや仮想ファイルシステムを通じてネットワーク上のデータを扱う機能も持ちます。GeoDjangoはGDALの一部機能をPythonから扱えるようにしています。

問題があるDjango 5.2.16では、細工した値が空間検索へ渡された場合、GDALの処理によって次の動作が発生する可能性がありました。

攻撃者が細工した検索値を送信
          │
          ▼
GeoDjangoの空間検索
          │
          ▼
GDALRasterとして解釈
          │
          ├─ ファイル系の処理
          │    └─ Django実行ユーザーの権限でファイル作成
          │
          └─ ネットワーク系の処理
               └─ Django実行ユーザーの権限でURLへ接続

Django公式は、利用するラスタードライバーによっては、サーバー上へのファイル書込みや、Djangoプロセスからのネットワークリクエストが発生すると説明しています。

ファイル書込み先や、その後のアプリケーション動作によっては、リモートコード実行へ発展する可能性があります。

RCEは無条件に成立するのか

無条件には成立しません。

今回の問題は、ファイルを書き込んだ時点で必ずコードが実行される脆弱性ではありません。

サーバー側ファイル書込み
          │
          ▼
Pythonや別プロセスが読み込む場所へ書き込める
          │
          ▼
書き込んだファイルが設定・コードとして読み込まれる
          │
          ▼
条件がそろった場合にコード実行

代表的な成立条件は次のとおりです。

  • GeoDjangoを使用している

  • 空間フィールドを持つモデルがある

  • GDALまたはラスタードライバーを使用している

  • 攻撃者の入力が空間検索へ到達する

  • Djangoプロセスに対象パスへの書込み権限がある

  • 書き込まれたファイルが後から実行または読み込まれる

Django Admin経由の代表的な攻撃経路では、次の権限も必要です。

  • Django Adminへログインできるstaffユーザー

  • 空間フィールドを持つ登録済みモデルの閲覧権限

Django公式は、Adminの変更一覧にある検索条件がModelAdmin.lookup_allowed()を通じて利用できるため、空間フィールドを含むモデルの閲覧権限を持つstaffユーザーから到達可能だったと説明しています。

SSRFとは

SSRFは、攻撃者がWebサーバーを代理として別のURLへ接続させる攻撃です。

たとえるなら、外部の人が社内の受付担当者へ「この社内資料を取ってきてください」と依頼し、外部から直接入れない場所へ受付担当者を行かせる状態です。

正式にはServer-Side Request Forgeryと呼ばれ、サーバーから内部ネットワーク、管理API、クラウドメタデータ、外部サービスなどへ意図しないリクエストを送信させます。

今回の脆弱性では、通信元はDjangoプロセスです。そのため、外部から直接接続できないURLでも、Djangoコンテナから接続可能であれば影響を受ける可能性があります。

Django 5.2.17での修正

Django 5.2.17では、空間検索で次の値が拒否されます。

  • dict

  • 有効なGEOSGeometryではない文字列

  • シリアライズされた辞書など、ジオメトリではない文字列

この変更はセキュリティ上必要な後方互換性のない変更です。

従来、辞書や文字列を空間検索値として渡していたアプリケーションでは、更新後にエラーが発生する可能性があります。信頼できるラスターを使用する場合は、入力を検証したうえで、アプリケーション側が明示的に適切なオブジェクトへ変換する必要があります。


CVE-2026-15337:長大な言語コードによるメモリDoS

何が問題なのか

Djangoには、指定された言語コードが有効かどうかを確認するcheck_for_language()があります。

問題があるDjango 5.2.16では、非常に長い言語コードを多数送信すると、それぞれの値がインメモリキャッシュのキーとして保存されました。

長大で異なる言語コードを繰り返し送信
                │
                ▼
check_for_language()
                │
                ▼
各文字列がキャッシュキーとして保存
                │
                ▼
Djangoワーカーのメモリ使用量が増加

言語コードは、django.views.i18n.set_language()へ送信されたPOSTデータから到達します。

ただし、set_language()はデフォルトで公開されていません。また、リクエストサイズはDATA_UPLOAD_MAX_MEMORY_SIZEで制限され、キャッシュの登録数にも上限があります。

このため、Djangoの評価はLowです。

Django 5.2.17での修正

Django 5.2.17では、500文字を超える言語コードをキャッシュへ渡す前に拒否します。

影響を受けやすい環境

次の構成では確認が必要です。

  • django.conf.urls.i18nをURL設定へ追加している

  • set_language()を独自URLへ登録している

  • 誰でも言語変更リクエストを送信できる

  • NginxやCloudflareでリクエスト頻度を制限していない

  • メモリ容量が小さいVPSで複数のDjangoワーカーを動かしている

GeoDjangoを利用していない環境でも、この脆弱性は関係します。


CVE-2026-15830:GeometryCollectionによるプロセスクラッシュ

何が問題なのか

GeoDjangoのGEOSGeometryは、WKTやWKBなどの形式で記述された図形を解析します。

GeometryCollectionは、複数の図形をまとめる入れ物です。

たとえるなら、箱の中へ別の箱を入れ、その箱の中へさらに箱を入れ続けられる構造です。

GEOMETRYCOLLECTION(
  GEOMETRYCOLLECTION(
    GEOMETRYCOLLECTION(
      ...
    )
  )
)

問題があるDjango 5.2.16では、非常に深く入れ子になったGEOMETRYCOLLECTIONを解析すると、背後のGEOSライブラリで再帰処理が続き、セグメンテーションフォルトが発生する可能性がありました。

セグメンテーションフォルトが発生すると、処理中のDjangoワーカープロセスが異常終了する可能性があります。リクエストを繰り返されると、サービス拒否につながります。

影響する入力

Django公式は、次の経路が影響を受けると説明しています。

  • WKT形式

  • WKB形式

  • 空間フィールドに対する検索

  • GeometryFieldフォームフィールド

GeoJSONはGDALで解析されるため、この問題の対象外です。

Django 5.2.17での修正

Django 5.2.17では、次の上限が追加されました。

入力形式上限
WKTGeometryCollectionの深さ198
WKBGeometryCollectionの総数198

必要な場合は、新しく追加されたmax_geom_collections引数で上限を調整できます。

上限を大きくすると再びリソース消費が増える可能性があります。実際に198を超える正当なデータが必要か確認してから変更してください。


CVE-2026-15920:Django AdminのURLFieldによる格納型XSS

何が問題なのか

Django Adminは、モデルのURLFieldを変更一覧や読み取り専用フィールドへ表示するとき、クリック可能なリンクへ変換します。

問題があるDjango 5.2.16では、保存されているURLのスキームが安全かどうかを表示時に再検証していませんでした。

不正なURLがデータベースへ保存されると、Django Admin上でもリンクとして表示される可能性がありました。

外部データや独自APIから不正URLを保存
                │
                ▼
Django AdminがURLFieldをリンクとして表示
                │
                ▼
管理者がリンクをクリック
                │
                ▼
管理者のブラウザー上でスクリプトが実行される可能性

これは格納型XSSです。

たとえるなら、危険な命令を書いた紙を共有棚へ保存し、後から管理者がその紙を開いたときに命令が実行される状態です。

正式にはStored Cross-Site Scriptingと呼ばれ、不正な入力がデータベースなどへ保存され、別の利用者が表示または操作したときにスクリプトが実行される問題です。

Django公式は、URLFieldの値が安全なURLとして検証されないままリンクへ変換されていたと説明しています。

通常のフォームを使っていれば安全なのか

通常のModelFormやDjango Adminの編集フォームでは、URLFieldのバリデーションが実行されます。

しかし、次の処理ではフォーム検証を通らない場合があります。

  • QuerySet.update()

  • bulk_create()

  • CSVからの一括取込み

  • 外部APIからの自動同期

  • スクレイピング結果の直接保存

  • 独自のデシリアライズ処理

  • SQLを使った直接更新

  • バリデーションを省略した管理コマンド

したがって、フォームがあることだけを理由に、データベース内のすべてのURLが安全であるとは判断できません。

攻撃成立条件

代表的な成立条件は次のとおりです。

  • 危険なURLField値をデータベースへ保存できる

  • 対象のURLFieldがDjango Adminに表示される

  • 管理者が表示されたリンクをクリックする

保存されただけで即座にコードが実行されるとは限りません。代表的な攻撃では、管理者のクリックが必要です。

Django 5.2.17での修正

Django 5.2.17では、URLFieldをリンクへ変換する前にURLValidatorで検証します。

検証に失敗したURLは、クリック可能なリンクではなく通常のテキストとして表示されます。


Django 5.2.16環境への影響を判断する

現在の環境がDjango 5.2.16であるため、バージョン上は今回の4件の修正対象です。

ただし、実際に攻撃経路へ到達できるかどうかは機能ごとに異なります。

環境・機能関係する脆弱性判断
Django 5.2.16全4件更新が必要
GeoDjangoを未使用CVE-2026-15307、CVE-2026-15830通常は直接到達しない
PostGISを使用GIS関連2件モデルと検索処理を確認
GDALRasterを使用CVE-2026-15307優先確認
Django Adminを使用CVE-2026-15920URLFieldを確認
空間モデルをAdminへ登録CVE-2026-15307staff権限を確認
set_language()を未登録CVE-2026-15337代表的経路は到達しない
外部データをURLFieldへ保存CVE-2026-15920検証処理を確認
AdminをVPN内へ制限GIS・XSSリスクは下がるが更新は必要
コンテナがrootで動作CVE-2026-15307ファイル書込み時の影響が拡大
外向き通信を無制限に許可CVE-2026-15307SSRFの到達範囲が広がる

確認方法

1. Djangoのバージョンを確認する

目的

稼働中のDjangoが5.2.16か、修正版の5.2.17かを確認します。

実行場所

Djangoコンテナを起動しているDockerホストで実行します。

コマンド

docker compose exec django python -m django --version

インストール元も確認する場合は次を実行します。

docker compose exec django python -m pip show Django

正常例

5.2.17

対応が必要な例

5.2.16

判断方法

  • 5.2.17:今回の4件は修正済み

  • 5.2.16以下:更新が必要

  • 6.0.7以下:6.0.8以上への更新が必要

  • 開発版やRC版:本番利用方針を再確認する


2. GeoDjangoを利用しているか確認する

目的

CVE-2026-15307とCVE-2026-15830の攻撃経路が存在するか確認します。

実行場所

Dockerホストで実行します。

コマンド

docker compose exec django python manage.py shell -c \
'from django.conf import settings; print("django.contrib.gis" in settings.INSTALLED_APPS)'

正常例

GeoDjangoを使用していない場合です。

False

要確認例

True

判断方法

Trueの場合は、GeoDjango関連のモデル、フォーム、API、管理画面を詳しく確認します。

ただし、Falseでもアプリケーションコードから一部のGISクラスを直接インポートしている可能性があります。続けてコード検索を行います。

grep -RInE \
'django\.contrib\.gis|GeometryField|RasterField|GEOSGeometry|GDALRaster' \
--include='*.py' \
--exclude-dir=.git \
--exclude-dir=.venv \
--exclude-dir=venv \
.

正常例

何も表示されない場合は、アプリケーションコードでGIS機能を利用していない可能性が高いと判断できます。

要確認例

./maps/models.py:18: location = models.GeometryField()
./maps/views.py:42: GEOSGeometry(request.data["geometry"])

表示された場合は、外部入力が検証されず空間検索やGEOSGeometryへ渡されていないか確認します。


3. 空間フィールドを持つモデルを確認する

目的

実際に登録されているGISフィールドを一覧化します。

実行場所

Djangoコンテナ内で実行します。

コマンド

docker compose exec django python manage.py shell <<'PY'
from django.apps import apps

for model in apps.get_models():
    for field in model._meta.get_fields():
        module = field.__class__.__module__
        if module.startswith("django.contrib.gis"):
            print(
                f"{model._meta.label}.{field.name}: "
                f"{field.__class__.__name__}"
            )
PY

正常例

GeoDjangoを使っていない場合は何も表示されません。

要確認例

maps.MapArea.geometry: PolygonField
maps.RasterLayer.image: RasterField

判断方法

表示されたモデルについて、次を確認します。

  • Django Adminへ登録されているか

  • staffユーザーに閲覧権限が付与されているか

  • URLクエリから動的な検索条件を受け取っているか

  • APIの値をそのままfilter()へ渡していないか

  • WKTやWKBの入力上限を設けているか


4. 言語切替ビューを確認する

目的

CVE-2026-15337の代表的な入力経路であるset_language()が公開されているか確認します。

実行場所

Djangoプロジェクトのソースコードがあるディレクトリで実行します。

コマンド

grep -RInE \
'set_language|django\.views\.i18n|django\.conf\.urls\.i18n' \
--include='*.py' \
--exclude-dir=.git \
.

正常例

多言語切替を使用していない環境では、結果が表示されません。

要確認例

config/urls.py:24:path("i18n/", include("django.conf.urls.i18n"))

判断方法

URL設定が見つかった場合は、次を確認します。

  • 外部からPOSTできるか

  • CloudflareやNginxでレート制限しているか

  • リクエストボディ上限が設定されているか

  • 本当に言語切替機能が必要か

Django 5.2.17へ更新すれば500文字を超える言語コードは早期に拒否されますが、不要なエンドポイントを公開しない設計も重要です。


5. URLFieldを持つモデルを確認する

目的

CVE-2026-15920の影響を受ける可能性があるモデルを一覧化します。

実行場所

Djangoコンテナ内で実行します。

コマンド

docker compose exec django python manage.py shell <<'PY'
from django.apps import apps
from django.db.models import URLField

for model in apps.get_models():
    for field in model._meta.get_fields():
        if isinstance(field, URLField):
            print(f"{model._meta.label}.{field.name}")
PY

正常例

URLFieldが存在しない場合は何も表示されません。

要確認例

diary.Reference.url
accounts.Profile.website
security.ThreatSource.source_url

判断方法

表示されたモデルについて、次を確認します。

  • Django Adminへ登録されているか

  • 外部APIやCSVから値を取り込んでいるか

  • フォームやシリアライザーの検証を通しているか

  • update()bulk_create()で直接保存していないか

  • 管理者がリンクをクリックする運用になっているか


6. バリデーションを迂回しやすい保存処理を検索する

目的

URLFieldや空間入力が検証を通らず保存される経路を確認します。

実行場所

プロジェクトのソースコードがあるディレクトリで実行します。

コマンド

grep -RInE \
'bulk_create|bulk_update|\.update\(|raw\(|cursor\.execute|deserialize' \
--include='*.py' \
--exclude-dir=.git \
--exclude-dir=.venv \
.

正常例

検索結果があっても、固定値だけを扱っている場合や、事前検証を実施している場合は問題ありません。

要確認例

Reference.objects.filter(pk=reference_id).update(
    url=request.data["url"]
)

判断方法

利用者や外部サービスから受け取った値を直接保存している場合は、明示的な検証を追加します。

URLの場合は、例えばURLValidatorを保存前に実行します。

from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

validate_url = URLValidator(
    schemes=["https"],
)

def validate_external_url(value: str) -> str:
    try:
        validate_url(value)
    except ValidationError as exc:
        raise ValueError("許可されていないURLです。") from exc
    return value

https以外が必要な場合は、必要性を確認して許可するスキームを限定してください。


Django 5.2.17への更新方法

更新前の注意事項

Django 5.2.16から5.2.17は同じ5.2系列のパッチ更新です。

ただし、CVE-2026-15307の修正では、空間検索へ辞書や不正な文字列を渡す処理が拒否されます。この動作に依存したコードがある場合は、更新後にエラーになる可能性があります。

本番更新前に、次を準備してください。

  • PostgreSQLのバックアップ

  • ユーザーアップロードファイルのバックアップ

  • 現在稼働中のDockerイメージタグ

  • 現在のrequirements.txtまたはロックファイル

  • ロールバック手順

  • ステージング環境でのテスト結果


1. 現在の依存関係を保存する

目的

更新前の状態を記録し、問題発生時に差分を確認できるようにします。

実行場所

Dockerホストで実行します。

コマンド

docker compose exec django python -m pip freeze \
  > requirements-before-django-5.2.17.txt

正常例

test -s requirements-before-django-5.2.17.txt \
  && echo "依存関係を保存しました"
依存関係を保存しました

異常例

ファイルが空の場合、対象コンテナ名やPython環境が正しいか確認します。


2. PostgreSQLをバックアップする

目的

更新中に予期しない問題が起きた場合にデータを復元できるようにします。

実行場所

Dockerホストで実行します。

コマンド例

環境に合わせてデータベース名とユーザー名を変更してください。

mkdir -p backups

docker compose exec -T postgres \
  pg_dump \
  -U app_user \
  -d app_database \
  -Fc \
  > "backups/django-update-$(date +%Y%m%d-%H%M%S).dump"

正常確認

ls -lh backups/

バックアップファイルのサイズが0バイトでないことを確認します。

注意

バックアップを作成しただけでは復元可能とは断定できません。

可能であれば、検証用PostgreSQLへリストアして、次のコマンドが成功することを確認してください。

pg_restore --list backups/対象ファイル.dump | head

3. Djangoのバージョン指定を変更する

requirements.txtを使用している場合は、次のように変更します。

Django==5.2.17

範囲指定を使用する場合は、意図しないDjango 6系列への更新を防ぎます。

Django>=5.2.17,<5.3

本番環境では、再現性を高めるため、ロックファイルまたは完全なバージョン固定を推奨します。

pip install -U Djangoだけを実行すると、設定によっては別のリリース系列へ更新される可能性があります。LTS系列を維持する場合は更新先を明示してください。


4. Dockerイメージを再ビルドする

目的

実行中コンテナへ直接インストールするのではなく、修正版を含む再現可能なイメージを作成します。

実行場所

Dockerホストで実行します。

コマンド

docker compose build django

キャッシュの影響を除外して完全に再構築する場合は次を実行します。

docker compose build --no-cache django

正常例

ビルドの最後でエラーが発生せず、イメージが作成されます。

異常例

Could not find a version that satisfies the requirement

この場合は、Pythonバージョン、パッケージインデックス、プロキシ設定、依存関係の競合を確認します。


5. 新しいイメージのDjangoバージョンを確認する

目的

本番へ反映する前に、新しいイメージへDjango 5.2.17が入っていることを確認します。

コマンド

docker compose run --rm django python -m django --version

正常例

5.2.17

異常例

5.2.16

5.2.16のままの場合は、次を確認します。

  • Dockerfileが正しいrequirements.txtをコピーしているか

  • 古いロックファイルが優先されていないか

  • マルチステージビルドで古い仮想環境をコピーしていないか

  • Docker BuildKitのキャッシュが残っていないか


6. Djangoのシステムチェックを実行する

目的

設定やアプリ登録に明らかな問題がないか確認します。

コマンド

docker compose run --rm django python manage.py check

本番向け設定も確認します。

docker compose run --rm django \
  python manage.py check --deploy

正常例

System check identified no issues (0 silenced).

注意

check --deployは、HTTPSやCookie設定などについて警告を出す場合があります。

警告を無視するのではなく、現在のCloudflare、Nginx、TLS終端構成を踏まえて、一つずつ妥当性を確認してください。Django公式も、本番環境ではDEBUG=False、適切なALLOWED_HOSTS、データベースとキャッシュへの接続制限、バックアップなどを求めています。


7. マイグレーション差分を確認する

目的

意図しないモデル変更が混入していないことを確認します。

コマンド

docker compose run --rm django \
  python manage.py makemigrations --check --dry-run

適用予定のマイグレーションも確認します。

docker compose run --rm django \
  python manage.py migrate --plan

正常例

No changes detected

または、事前に把握しているマイグレーションだけが表示されます。

異常例

今回のDjango更新と無関係な多数のモデル差分が表示された場合は、そのまま本番へ反映しないでください。


8. テストを警告付きで実行する

Django公式は、更新時に非推奨警告を表示してテストする方法として-Waを案内しています。

コマンド

docker compose run --rm django \
  python -Wa manage.py test

pytestを使用している場合は次のように実行します。

docker compose run --rm django \
  env PYTHONWARNINGS=always \
  pytest --capture=no

正常例

  • テストがすべて成功する

  • 新しい例外が発生しない

  • 空間検索の既存機能が動作する

  • Adminの一覧画面が表示できる

異常例

空間検索で次のような処理に依存していた場合、Django 5.2.17でエラーになる可能性があります。

Model.objects.filter(
    raster_field__intersects={
        "driver": "GTiff",
        "source": "...",
    }
)

辞書や文字列を利用する必要がある場合は、信頼できる入力かを検証し、Django 5.2.17の公式ドキュメントに従って明示的に適切なGISオブジェクトへ変換します。


9. 本番へ反映する

事前テストに成功した後で、新しいコンテナを起動します。

docker compose up -d --no-deps django

Nginxなどもイメージや設定が変更されている場合は、対象サービスを含めて起動します。

docker compose up -d

起動状態の確認

docker compose ps

ログ確認

docker compose logs --tail=200 django

エラーを追跡する場合は次を実行します。

docker compose logs -f django

更新後の動作確認

基本的な確認項目

確認対象正常条件
トップページHTTP 200で表示される
ログイン正常に認証できる
ログアウトセッションが終了する
Django Admin一覧・詳細・編集画面が表示される
URLField正常なHTTPSリンクだけがリンク表示される
API主要エンドポイントが期待したJSONを返す
Redisキャッシュとセッションが正常に動作する
WebSocket接続、再接続、メッセージ送信が成功する
ファイルアップロードサイズ上限内のファイルを保存できる
メールパスワードリセットや通知が届く
GIS地図検索、空間検索、保存、表示が成功する

HTTPヘルスチェック

目的

更新後に外部からWebサイトへ接続できるか確認します。

コマンド

curl -fsS -o /dev/null \
  -w 'HTTP=%{http_code} TIME=%{time_total}\n' \
  https://kurutann.com/

正常例

HTTP=200 TIME=0.245

異常例

HTTP=502

502の場合は、NginxからDjangoコンテナへの接続、Gunicornの起動状態、ソケットまたはポート設定を確認します。


Djangoバージョンの最終確認

docker compose exec django python -m django --version
5.2.17

本番コンテナ内で5.2.17が確認できるまで、更新完了とは判断しないでください。


管理画面の確認

ステージング環境で、次を確認します。

  1. URLFieldを持つモデルの変更一覧を開く

  2. 正常なHTTPS URLがリンクとして表示されることを確認する

  3. 検証に失敗する値がリンクにならないことを確認する

  4. 空間フィールドを持つモデルの絞り込みを確認する

  5. 制限付きstaffユーザーの権限を確認する

本番データへ危険なURLを登録して試験しないでください。

専用のテストデータとステージング環境を使用してください。


GIS機能の確認

GeoDjangoを使用している場合は、次を確認します。

  • WKTの登録

  • WKBの登録

  • GeoJSONの登録

  • 空間検索

  • 距離検索

  • 範囲検索

  • Django Adminのフィルター

  • GISフォームの入力

  • ラスターデータの読込み

  • 外部ストレージからの読込み

Django 5.2.17では、空間検索へ渡せる入力型が厳しくなっています。

更新後にGIS機能だけ失敗する場合は、セキュリティ修正によって不正または曖昧な入力が拒否されている可能性があります。検証を無効化するのではなく、入力形式を明示的に変換してください。


すぐに更新できない場合の暫定対策

Django 5.2.17への更新が第一選択です。

暫定対策だけで安全になったとは判断しないでください。

GeoDjango関連

  • 空間フィールドを持つモデルをDjango Adminから一時的に外す

  • 対象モデルのview権限を必要最小限へ変更する

  • 管理画面をWireGuardや社内VPNからのみ許可する

  • 未信頼入力を空間検索へ渡さない

  • WKT、WKB、リクエストボディのサイズを制限する

  • Djangoコンテナを非rootで実行する

  • ルートファイルシステムを可能な範囲でread-onlyにする

  • Djangoコンテナの外向き通信を必要な宛先だけに制限する

言語切替関連

  • 使用していないset_language()をURL設定から外す

  • 言語切替URLへレート制限を設定する

  • Nginxのリクエストボディ上限を設定する

  • Cloudflareで異常なPOST頻度を制限する

URLField関連

  • 外部データ保存時にURLValidatorを実行する

  • URLスキームをhttpsへ限定する

  • 管理画面で不明なリンクをクリックしない

  • バリデーションを通さない一括登録処理を停止する

  • URLFieldを読み取り専用テキストとして独自表示する


WAF・IPS・EDRによる補助対策

補助できる範囲

脆弱性WAF・IPSで可能な補助限界
CVE-2026-15307異常な空間検索値、管理画面への不審なクエリを検知正当な形式との区別が難しく、符号化された入力を見逃す可能性がある
CVE-2026-15337長大なPOST、同一URLへの高頻度アクセスを制限低頻度で分散されたリクエストには弱い
CVE-2026-15830大量のGEOMETRYCOLLECTIONを含むWKTを検知WKBなどのバイナリ形式は単純な文字列検査が難しい
CVE-2026-15920不審なURLスキームを入力時に遮断データベースへ既に保存された値や管理者の操作までは完全に防げない

EDR・コンテナ監視で見るべき兆候

CVE-2026-15307対策では、Djangoプロセスの振る舞いを監視します。

  • 通常使わないディレクトリへのファイル作成

  • Pythonパッケージディレクトリへの書込み

  • テンプレートディレクトリへの書込み

  • /tmpへの不審な実行ファイル作成

  • Djangoコンテナから内部IPへの突然の接続

  • クラウドメタデータ相当アドレスへの接続

  • 通常利用しない外部ドメインへのアクセス

  • Djangoワーカー直後の子プロセス生成

  • GEOS関連のセグメンテーションフォルト

  • Djangoワーカーの異常なメモリ増加

Cloudflare WAF、IPS、EDRは多層防御として有効です。

ただし、今回の4件はDjango内部の処理に問題があります。WAFルールへ追加しただけで修正済みとは判断せず、Django 5.2.17への更新を完了させてください。


再発防止

1. Django 5.2系列の最新パッチを継続的に追跡する

Django 5.2 LTSは2028年4月までサポートされます。

ただし、Django 5.2.16を固定したまま2028年まで安全に使えるという意味ではありません。セキュリティ修正版が公開されるたびに、同じ5.2系列の最新パッチへ更新する必要があります。

2. パッチ更新の社内基準を決める

実務上の目安として、次の対応期限を決めておくと判断が遅れにくくなります。

深刻度推奨する社内目標
Critical原則24時間以内
High24~48時間以内
Moderate3営業日以内
Low次回定期メンテナンスまで
悪用確認済み深刻度にかかわらず緊急対応

これはDjango公式の期限ではなく、運用ルールの一例です。システムの重要度、公開範囲、メンテナンス可能時間に合わせて調整してください。

3. CIで依存関係を検査する

CIへ次の処理を追加します。

  • python -m pip check

  • テストスイート

  • python -Wa manage.py test

  • python manage.py check

  • python manage.py check --deploy

  • 依存関係の脆弱性スキャン

  • SBOMの生成

  • コンテナイメージの脆弱性スキャン

4. GeoDjangoを別のリスク領域として管理する

GeoDjangoを使用する場合は、通常のORM入力とは別に次を管理します。

  • WKT、WKB、GeoJSONの最大サイズ

  • GeometryCollectionの最大数

  • GDALドライバー

  • GDAL仮想ファイルシステム

  • ファイル書込み先

  • 外向きネットワークアクセス

  • Django Adminの権限

  • 空間検索へ渡せる入力型

5. URLFieldへ保存する値を入口で検証する

表示時のエスケープだけに依存しないでください。

外部入力
   │
   ▼
スキームと形式を検証
   │
   ▼
許可されたURLだけを保存
   │
   ▼
表示時にも再検証

入力時と表示時の両方で検証することで、一方の処理が迂回された場合にも影響を小さくできます。

6. Django Adminを一般公開しない

可能な場合は、次を組み合わせます。

  • VPNまたはWireGuard

  • IP制限

  • 多要素認証

  • staff権限の定期棚卸し

  • モデル単位の最小権限

  • 管理画面操作ログ

  • 管理画面URLへのレート制限

  • 不要なモデルをAdminへ登録しない


注意点・よくある誤解

「LTSだから5.2.16のままでも安全」は誤り

LTSは、対象系列へ長期間セキュリティ修正が提供される仕組みです。

古いパッチバージョンが自動的に修正される仕組みではありません。

「RCEと書かれているので全Djangoサイトが即侵害される」は誤り

今回のRCEは、GeoDjango経由のファイル書込みが特定の条件下でコード実行へ発展する可能性を示しています。

GeoDjangoを利用していない一般的なDjangoサイトで、トップページへアクセスするだけでRCEが成立する問題ではありません。

「GeoDjangoを使っていないから更新不要」は誤り

GeoDjangoを使っていなくても、次の2件が関係します。

  • CVE-2026-15337

  • CVE-2026-15920

さらに、セキュリティパッチは既知の問題をまとめて解消するため、Django 5.2.17への更新は必要です。

「AdminをVPN内に置けば修正不要」は誤り

VPNは攻撃可能な利用者を減らしますが、次の問題は残ります。

  • 内部アカウントの侵害

  • 権限設定の誤り

  • 外部APIからの不正データ保存

  • 独自の空間検索API

  • 管理者による不正リンクのクリック

「Cloudflare WAFがあるから更新不要」は誤り

WAFはHTTPリクエストを検査できますが、Django内部の型変換、GDALドライバー、GEOSの再帰処理、保存済みURLの表示処理を完全には再現できません。

WAFは緩和策であり、修正版への更新が本対応です。


悪用状況について

Django公式の2026年8月4日の告知には、実環境での悪用が確認されたという記載はありません。

ただし、公式告知に悪用の記載がないことは、世界中で悪用が一切行われていないことを証明するものではありません。

2026年8月5日時点では、次のように区別する必要があります。

確認できる事実

  • Django 5.2.16は4件の修正対象である

  • Django 5.2.17が公開されている

  • CVE-2026-15307はHigh評価である

  • ファイル書込み、SSRF、条件付きRCEの可能性がある

  • Django公式は速やかな更新を推奨している

確認できないこと

  • kurutann.comが実際に攻撃を受けたか

  • 公開されていない攻撃で悪用されているか

  • すべてのGDAL構成で同じ方法のRCEが成立するか

  • WAFだけで全攻撃パターンを遮断できるか

不明な点を推測で断定せず、バージョン更新、コード確認、ログ確認を組み合わせて判断してください。


まとめ

Django 5.2.16には、次の4件のセキュリティ問題があります。

  • GeoDjangoの空間検索によるファイル書込み・SSRF・条件付きRCE

  • 長大な言語コードによるメモリDoS

  • 入れ子のGeometryCollectionによるGEOSクラッシュ

  • Django AdminのURLFieldによる格納型XSS

現在Django 5.2.16 LTSを利用している場合は、Django 5.2.17 LTSへ更新してください。

GeoDjangoを使用していない場合、CVE-2026-15307とCVE-2026-15830の代表的な攻撃経路は存在しない可能性があります。しかし、残る2件への対応と、将来の安全な運用のためにパッチ更新は必要です。

更新後は、バージョン表示だけで完了とせず、Django Admin、URLField、GIS、API、認証、Redis、WebSocket、ファイルアップロードまで動作確認してください。

Cloudflare WAF、IPS、EDR、コンテナ制限、外向き通信制限は重要な補助対策です。しかし、脆弱なDjango本体を修正するものではありません。


FAQ

Django 5.2.16は今回の脆弱性の影響を受けますか

はい。

Django 5.2.17の公式リリースノートは、Django 5.2.16に存在するHigh 1件、Moderate 2件、Low 1件を修正したと明記しています。

Django 5.2.17へ更新すればDjango 6へ移行する必要はありませんか

今回の4件への対応だけであれば、Django 5.2.17への更新で対応できます。

Django 5.2はLTSであり、2028年4月まで延長サポートされる予定です。

GeoDjangoを使っていなければRCEの影響はありませんか

CVE-2026-15307の代表的な攻撃経路はGeoDjangoの空間検索です。

django.contrib.gis、空間フィールド、GDALRaster、独自GIS処理を使用していない場合、通常は直接到達しません。

ただし、コード検索とインストール済み機能の確認を行ってから判断してください。

Django Adminを無効にしていればCVE-2026-15307は安全ですか

Django Admin経由の代表的な経路は閉じられます。

しかし、独自APIや検索画面が未信頼入力を空間検索へ渡している場合は、別の経路から到達する可能性があります。

CVE-2026-15920はリンクを表示しただけで発動しますか

Django公式の説明では、危険な値がクリック可能なリンクとして表示される問題です。

代表的な攻撃では、管理者がリンクをクリックする必要があります。

ただし、危険な値を保存できる経路自体も修正してください。

set_language()を使っていなければCVE-2026-15337は関係ありませんか

Django公式が示す入力経路は、デフォルトでは有効でないset_language()です。

URLへ登録していなければ代表的な経路はありません。ただし、check_for_language()を独自処理から呼び出している場合は確認してください。

Dockerコンテナ内で直接pip installしてもよいですか

一時的な検証以外では推奨しません。

実行中コンテナへ直接インストールすると、コンテナを再作成した際に更新が失われます。requirementsやロックファイルを更新し、Dockerイメージを再ビルドしてください。

データベースのマイグレーションは必要ですか

プロジェクト側のモデル変更状況によって異なります。

makemigrations --check --dry-runmigrate --planを実行し、意図しない差分がないことを確認してください。

更新後に空間検索が失敗するのはなぜですか

CVE-2026-15307の修正により、空間検索へ渡せる入力型が制限されました。

辞書や、有効なGEOSGeometryではない文字列を空間検索へ渡している場合は、入力を検証し、適切なGISオブジェクトへ明示的に変換する必要があります。


参考情報

Django公式のセキュリティ情報

Django 6.0.8および5.2.17のセキュリティリリース

Django Software Foundationによる今回の公式セキュリティ告知です。

CVE-2026-15307、CVE-2026-15337、CVE-2026-15830、CVE-2026-15920の影響、深刻度、修正内容、影響するDjango系列がまとめられています。

https://www.djangoproject.com/weblog/2026/aug/04/security-releases/

Django 5.2.17リリースノート

Django 5.2.16から5.2.17へ更新した際の変更内容を確認できます。

GeoDjangoの空間検索で受け入れられる値の変更、言語コードの500文字制限、GeometryCollectionの上限、Django AdminのURLField検証が記載されています。

https://docs.djangoproject.com/en/5.2/releases/5.2.17/

Djangoのセキュリティポリシー

Djangoにおける脆弱性の深刻度、セキュリティリリースの対象系列、脆弱性の報告方法を確認できます。

https://docs.djangoproject.com/en/dev/internals/security/

Djangoのサポート対象バージョン

Django 5.2 LTSのサポート期間と、現在利用可能な正式リリースを確認できます。

https://www.djangoproject.com/download/


CVE情報

CVE-2026-15307

GeoDjangoの空間検索を通じて、サーバー側ファイル書込みやSSRFが発生する可能性がある脆弱性です。

環境や書込み先などの条件がそろった場合、リモートコード実行へ発展する可能性があります。

NVD:

https://nvd.nist.gov/vuln/detail/CVE-2026-15307

Debian Security Tracker:

https://security-tracker.debian.org/tracker/CVE-2026-15307

CVE-2026-15337

django.utils.translation.check_for_language()へ多数の異なる長大な言語コードを渡すことで、Djangoプロセスのメモリを消費させる可能性がある脆弱性です。

NVD:

https://nvd.nist.gov/vuln/detail/CVE-2026-15337

Debian Security Tracker:

https://security-tracker.debian.org/tracker/CVE-2026-15337

CVE-2026-15830

深く入れ子になったGEOMETRYCOLLECTIONをGeoDjangoで解析すると、GEOSでセグメンテーションフォルトが発生する可能性がある脆弱性です。

NVD:

https://nvd.nist.gov/vuln/detail/CVE-2026-15830

Debian Security Tracker:

https://security-tracker.debian.org/tracker/CVE-2026-15830

CVE-2026-15920

安全でないURLスキームを含むURLFieldの値がDjango Adminでリンクとして表示され、管理者がクリックした場合に格納型XSSが発生する可能性がある脆弱性です。

NVD:

https://nvd.nist.gov/vuln/detail/CVE-2026-15920

Debian Security Tracker:

https://security-tracker.debian.org/tracker/CVE-2026-15920


Django 5.2系列の公式修正コミット

CVE-2026-15307の修正コミット

空間検索において、文字列や辞書が暗黙的にGDALRasterへ渡される処理を制限した修正です。

https://github.com/django/django/commit/115ffd0463a765ab1cc93de18e94b5459b8a300e

CVE-2026-15337の修正コミット

500文字を超える言語コードを、キャッシュされた言語検索へ渡す前に拒否する修正です。

https://github.com/django/django/commit/c72a5dbb64d0777f3f471f1be94e8b2ca91e0959

CVE-2026-15830の修正コミット

WKTとWKBで処理できるGEOMETRYCOLLECTIONの深さと総数に上限を追加した修正です。

https://github.com/django/django/commit/ba80833fa656dd09660b97c4429331067db1b080

CVE-2026-15920の修正コミット

Django AdminでURLFieldをリンクとして表示する前に、URLValidatorで検証する修正です。

https://github.com/django/django/commit/b9adb81339cc418f8f56b1050cca6dfec3ab6349


GeoDjango・GDALの公式資料

Django公式のGDAL API

GeoDjangoからGDALを利用する方法、GDALRaster、仮想ファイルシステム、ラスター処理の仕様を確認できます。

https://docs.djangoproject.com/en/5.2/ref/contrib/gis/gdal/

Django公式のGeoDjangoデータベースAPI

空間検索、GeometryField、RasterField、地理空間ルックアップの仕様を確認できます。

https://docs.djangoproject.com/en/5.2/ref/contrib/gis/db-api/

Django公式の空間ルックアップ一覧

GeoDjangoで利用できる空間検索と、検索値として扱われるジオメトリやラスターの仕様を確認できます。

https://docs.djangoproject.com/en/5.2/ref/contrib/gis/geoquerysets/

GDALのセキュリティ情報

GDALドライバー、外部データ、ネットワークアクセス、信頼できない入力を処理する際の注意点を確認できます。

https://gdal.org/en/stable/user/security.html

GDAL仮想ファイルシステム

GDALがローカルファイル以外のHTTP、クラウドストレージ、圧縮ファイルなどを扱う仮想ファイルシステムの仕様です。

https://gdal.org/en/stable/user/virtual_file_systems.html


Djangoの更新・本番運用資料

Djangoを新しいバージョンへ更新する方法

更新前のリリースノート確認、非推奨警告の表示、テスト方法など、Django公式のアップグレード手順です。

https://docs.djangoproject.com/en/5.2/howto/upgrade-version/

Djangoの本番デプロイチェックリスト

DEBUGSECRET_KEY、HTTPS、Cookie、データベース、キャッシュ、バックアップなど、本番環境で確認すべき項目がまとめられています。

https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/

Djangoの国際化機能

set_language()、言語選択、URL設定、翻訳機能の利用方法を確認できます。

https://docs.djangoproject.com/en/5.2/topics/i18n/translation/

set_language()ビュー

CVE-2026-15337の入力経路となる可能性がある、Django標準の言語切替ビューの仕様です。

https://docs.djangoproject.com/en/5.2/topics/i18n/translation/#the-set-language-redirect-view

URLValidator

DjangoがURLの形式と許可されたスキームを検証するURLValidatorの仕様です。

https://docs.djangoproject.com/en/5.2/ref/validators/#urlvalidator


パッケージ情報

PyPIのDjango 5.2.17

Django 5.2.17のパッケージ情報、配布ファイル、公開日時を確認できます。

https://pypi.org/project/Django/5.2.17/

Django公式GitHubリポジトリ

Django本体のソースコード、コミット履歴、ブランチ、タグを確認できます。

https://github.com/django/django


関連記事

Django 5.2.15以前の脆弱性と重大バグ

Django 5.2.16までに修正されたSQLインジェクション、共有キャッシュからの情報漏えい、ASGIのDoS、管理画面、メールなどの問題をまとめています。

https://kurutann.com/diary/detail/1724/

本記事は、上記記事の続報です。

2026年7月時点ではDjango 5.2.16が修正版でしたが、2026年8月4日にDjango 5.2.17が公開されたため、現在の更新先はDjango 5.2.17となります。


報道記事

GBHackers:Django Flaws Let Attackers Trigger RCE, SSRF, DoS, and XSS Attacks

今回の4件をRCE、SSRF、DoS、XSSの観点からまとめた報道記事です。

見出しだけでは攻撃成立条件が省略されているため、脆弱性の正確な影響判断にはDjango公式告知とリリースノートを優先してください。

https://gbhackers.com/django-flaws/


参照時の注意

脆弱性の影響範囲、修正版、後方互換性のない変更については、Django公式のセキュリティ告知とDjango 5.2.17リリースノートを一次情報として扱ってください。

NVDのCVSS評価や悪用状況は、公開直後には未評価または暫定値になっている場合があります。

報道記事や第三者の脆弱性データベースは概要把握に利用し、実際の更新判断ではDjango公式情報と修正コミットを確認してください。



読んだ内容を10問練習と実技で確認

記事で理解した用語を、StudyQuestの演習とクラウド実技ラボで定着させます。

10問練習 実技ラボ

コメント(0件)

まだコメントはありません。最初のコメントを投稿してください!

コメントを投稿