当社のAIエンジンNeutronが、UCバークレーのCyberGymベンチマークで97.1%のスコアを記録しました。 詳細を見る

ディープダイブ

ディープダイブ

Plone の未認証 RCE、6.2.3 で修正(Hotfix 20261110)

5 つの欠陥の連鎖により、匿名の訪問者が Plone 6.0 から 6.2 および旧版でコードを実行できます。11 月 10 日の更新がこれを塞ぎます。

要点

  • 5 つの欠陥の連鎖により、匿名の訪問者が Plone サイトでコードを実行できます。バージョン管理のモディファイアクラスは権限チェックなしで edit メソッドを公開しており、4 つのパッケージが Python モジュール全体を制限付きコードに開放しています。
  • サポート対象のすべてのリリースが影響を受けます。Plone 6.2、6.1、6.0 に加え、修正パッケージを通じて 4.3 までの旧版も対象です。
  • 主要な欠陥は CVSS v3.1 9.8 重大、CWE-862 と評価されています。CVE はまだ割り当てられておらず、悪用は確認されておらず、2026 年 11 月 11 日時点で CISA の Known Exploited Vulnerabilities カタログにも登録されていません。
  • 5 つのパッケージを修正版に更新するか、Products.PloneHotfix20261110 をインストールしてすべての Zope インスタンスを再起動してください。「修正方法」を参照してください。

影響を受けますか?

次の条件がすべて当てはまる場合に影響を受けます。

  • Plone 6.2、6.1、6.0、または 4.3 までの旧版を実行している。勧告はサポート対象のすべてのリリースを挙げ、旧版も影響を受けると述べています。
  • サイトに Products.CMFEditions がある。これは portal_modifier ツールを提供するバージョン管理パッケージで、Plone には既定で含まれます。
  • 攻撃者が HTTP でサイトに到達できる。入口は portal_modifier オブジェクトで、Zope のアクイジションにより任意のフォルダーの下から到達できます。

この連鎖はアカウントなしで動作します。欠陥の 1 つは編集者がバージョン管理されたコンテンツを保存したときにも実行されるため、直接公開されていないサイトにも内部経路が残ります。ベンダーはパッケージ更新の完全なセットを推奨される修正としています。修正パッケージはパッケージ更新を受けられない旧版を対象にします。

公式の plone/plone-backend コンテナイメージは Docker Hub で 486,034 回取得されており、この構成を実行する配備の多さを示す手がかりです。

ブランチ 影響を受けるバージョン 修正済みパッケージ
Plone 6.2 6.2.3 より前のすべてのリリース Products.CMFPlone 6.2.3、Products.CMFEditions 5.0.2、Products.MimetypesRegistry 4.0.2、plone.batching 3.0.3、plone.restapi 10.2.1
Plone 6.1 6.1.6 より前のすべてのリリース Products.CMFPlone 6.1.6、Products.CMFEditions 4.0.7、Products.MimetypesRegistry 3.0.2、plone.batching 2.0.8、plone.restapi 9.15.8
Plone 6.0 6.0.16 より前のすべてのリリース Products.CMFPlone 6.0.16、Products.CMFEditions 4.0.7、Products.MimetypesRegistry 3.0.2、plone.batching 2.0.8、plone.restapi 9.15.8
Plone 4.3 から 5.2 すべてのリリース パッケージ更新なし。Products.PloneHotfix20261110 をインストールする

Zope を実行する仮想環境または buildout から、インストール済みパッケージを確認します。

pip show Products.CMFPlone Products.CMFEditions Products.MimetypesRegistry plone.batching plone.restapi
# Buildout: print the pinned versions
bin/buildout annotate | grep -E 'Products.CMFPlone|Products.CMFEditions|Products.MimetypesRegistry|plone.batching|plone.restapi'
# Constraints or requirements files used to build the instance
grep -R -E 'Products.CMFPlone|Products.CMFEditions|Products.MimetypesRegistry|plone.batching|plone.restapi' constraints.txt requirements.txt buildout.cfg

Plone サイトのルートにある新しい @@check-modifier-conditions ページが、モディファイアの条件が変更されたかを確認する最短の方法です。Manager としてログインし、https://your-site/@@check-modifier-conditions を開きます。現在の条件を既定値と比較し、元に戻す選択肢を提示します。

修正方法

Plone のブランチに対応する行のすべてのパッケージを更新し、すべての Zope インスタンスを再起動します。旧版を実行している場合は、代わりに修正パッケージをインストールします。

  1. Plone 6.2 では修正済みセットをインストールします。 pip install -U "Products.CMFPlone==6.2.3" "Products.CMFEditions==5.0.2" "Products.MimetypesRegistry==4.0.2" "plone.batching==3.0.3" "plone.restapi==10.2.1"
  2. Plone 6.1 では修正済みセットをインストールします。 pip install -U "Products.CMFPlone==6.1.6" "Products.CMFEditions==4.0.7" "Products.MimetypesRegistry==3.0.2" "plone.batching==2.0.8" "plone.restapi==9.15.8"
  3. Plone 6.0 では修正済みセットをインストールします。 pip install -U "Products.CMFPlone==6.0.16" "Products.CMFEditions==4.0.7" "Products.MimetypesRegistry==3.0.2" "plone.batching==2.0.8" "plone.restapi==9.15.8"
  4. Buildout では [versions] セクションに同じバージョンを固定し、bin/buildout を再実行します。制約ファイルでは二重等号形式を使い、たとえば Products.CMFPlone==6.2.3 と書きます。
  5. 4.3 から 6.2 のうちパッケージ更新を受けられないリリースでは、修正パッケージをインストールし、すべての Zope インスタンスを再起動します。 pip install Products.PloneHotfix20261110 修正パッケージは Python 2.7 と Python 3 で動作します。パッケージインデックスがこの表記で見つからない場合は、正規化名 products-plonehotfix20261110 を使ってください。
  6. 最初の 1 つだけでなく、すべての Zope インスタンスを再起動します。修正はプロセス起動時に読み込まれます。

すぐに更新できない場合は、リバースプロキシで portal_modifier を含むすべての URL をブロックします。Zope のアクイジションによりオブジェクトは任意のフォルダーの下から到達できるため、サイトのルートだけでなくパスのどこでもブロックします。

  1. nginx では、包括的な location の前に正規表現の location を追加します。 location ~ portal_modifier { return 403; }
  2. mod_rewrite を使う Apache では、プロキシのルールの前に次のルールを追加します。 RewriteEngine On RewriteRule portal_modifier - [F,L]
  3. 更新後もルールを維持します。事前告知が推奨しており、コストはかかりません。

プロキシのルールは暫定措置です。Apache、nginx、Traefik は照合前にパーセントエンコーディングをデコードするため、/%70ortal_modifier も捕捉されます。Varnish はパスをデコードしないため、エンコード形式もルールに含める必要があります。このルールは、別の経路が制限付きコードに到達した場合のサンドボックス脱出を修正しません。

根本原因は何ですか?

連鎖は、Plone のバージョン管理モディファイアがメソッドを呼べる相手を宣言していなかったことから始まります。モディファイアはバージョン管理操作を包む SimpleItem です。Zope は docstring を持つメソッドを、セキュリティ宣言で保護されていなければ公開します。ConditionalModifier.edit と ConditionalTalesModifier.edit には宣言がなく、匿名の訪問者が呼び出せました。

5.0.1 の Products/CMFEditions/Modifiers.py にある脆弱なクラスは次のとおりです。

class ConditionalModifier(SimpleItem):
    """This is a wrapper for a modifier."""

    modifierEditForm = PageTemplateFile(
        "www/modifierEditForm.pt", globals(), __name__="modifierEditForm"
    )

    def edit(self, enabled=None, title="", REQUEST=None):
        """See IConditionalModifier."""
        self.title = title

        if enabled is not None and (
            enabled == "True" or (isinstance(enabled, bool) and enabled)
        ):
            self._enabled = enabled
        else:
            self._enabled = False

ConditionalTalesModifier はこれを継承し、条件を追加します。

class ConditionalTalesModifier(ConditionalModifier):
    """This is a wrapper with a tales condition for a modifier."""

    def edit(self, enabled=None, condition=None, title="", REQUEST=None):
        """See IConditionalTalesModifier."""
        ConditionalModifier.edit(self, enabled, title)
        if condition is not None and condition != self.getTalesCondition():
            self._condition = Expression(condition)

Expression(condition) は攻撃者の文字列を TALES 式としてコンパイルします。式は後で isApplicable の中で評価されます。バージョン管理の仕組みは、モディファイアを適用するかを決めるときにこのメソッドを呼びます。

    def isApplicable(self, obj, portal=None):
        """See IConditionalTalesModifier."""
        if not self._enabled or not self.getTalesCondition() or self.isBroken():
            return False

        context = createExpressionContext(obj, portal)
        return self._condition(context)

権限チェックの欠落だけで、匿名の訪問者が条件を変更して実行できます。連鎖の後半はサンドボックス脱出です。制限付き Python は、パッケージが明示的に公開した名前だけを公開するはずです。しかし 4 つのパッケージは allow_module でモジュール全体を開き、モジュール内のすべての名前を公開していました。そこにはインポートしたモジュールや関数も含まれます。

Products.CMFPlone の 6.2.2 は 3 つのモジュールを開いていました。

    allow_module("Products.CMFPlone.utils")
    # ...
    allow_module("Products.CMFPlone.browser.navtree")
    # ...
    allow_module("OFS.ObjectManager")

Products.MimetypesRegistry は common モジュールを開いていました。

allow_module("Products.MimetypesRegistry.common")

plone.batching は自身のパッケージを開いていました。

allow_module("plone.batching")

plone.restapi は標準ライブラリの json モジュールを開いていました。

allow_module("json")

json モジュールはシリアライズには無害ですが、一部の関数はオブジェクトの保護されたメソッドを呼べるため、制限付きコードができることも広げていました。重要なのはインポートのグラフです。この方法で開かれたモジュールは、インポートした補助関数も公開し、その補助関数が os に到達できます。ベンダーの勧告は、公開された名前により制限付きコードが os などのモジュールに到達し、サンドボックスを脱出できたと述べています。

どのように悪用されますか?

  1. 攻撃者は portal_modifier オブジェクトに要求を送り、edit メソッドを呼び出します。クラスにセキュリティ宣言がないため、このメソッドは公開されています。
  2. 要求は enabled と condition の値を設定します。ConditionalTalesModifier.edit は値をコンパイル済みの Expression として保存します。
  3. 攻撃者はモディファイアを実行するか、編集者がバージョン管理されたコンテンツを保存してバージョン管理の仕組みが isApplicable を呼ぶのを待ちます。
  4. isApplicable は保存された条件を、プロセスまたはコンテンツを保存した編集者の権限で評価します。
  5. 制限付き Python は通常、式をサンドボックスの境界で止めます。包括的な allow_module 宣言が os に至るモジュールとインポートを公開するため、式はサンドボックスを脱出してコマンドを実行します。
  6. コマンドは Zope プロセスのユーザーとして実行されます。既定の配備では、そのユーザーが Plone インスタンス、データベース接続、アップロード済みファイルを所有します。

公開されたエクスプロイトコードはありません。勧告は動作する概念実証が存在し、ベンダーと共有されたと述べていますが、要求の手順は公開していません。上記の手順は勧告の説明と修正済みパッケージのコード経路に従っています。

攻撃の流れは?

この攻撃は、1 つの未認証要求を保存された TALES 式に変え、広すぎるモジュール宣言を悪用してその式を制限付きサンドボックスの外で評価します。

flowchart LR A["匿名の訪問者"] --> B["portal_modifier の edit メソッド
権限宣言なし"] B --> C["TALES 条件を Expression
として保存"] C --> D["isApplicable が
条件を評価"] D --> E["allow_module が
インポート済み補助関数を公開"] E --> F["制限付き Python が os に到達"] F --> G["Zope プロセスのユーザーとしてコードを実行"]

攻撃者に何ができますか?

連鎖に到達した攻撃者は、Plone サイトを提供する Zope プロセスの権限でコードを実行できます。勧告は、匿名の経路でサーバー上のコードを実行できると述べています。同じ条件は、編集者がバージョン管理されたコンテンツを保存するときにその編集者の権限でも実行できます。

影響には次のものがあります。

  • サイトのコンテンツと、Zope プロセスが到達できるファイルの読み取りと変更。
  • データベース接続設定を含む、プロセスが利用できる設定と秘密情報の読み取り。
  • Plone のサービスアカウントとしてホスト上でコマンドを実行すること。
  • サイトを足がかりに、データベースや内部サービスに到達するネットワークへ侵入すること。

条件は「影響を受けますか?」と同じです。影響を受けるリリース、HTTP で到達できる portal_modifier ツール、そして更新もプロキシ遮断もないことです。CMFEditions の勧告は主要な欠陥を CVSS v3.1 9.8 重大、CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H、CWE-862 と評価しています。勧告は、この欠陥がホストの root 権限を与えるとは述べていません。サーバー上でコードが実行され、プロセスの権限がそのコードの範囲を制限すると述べています。

修正が機能する理由

修正は匿名の入口を閉じ、同じリリースでサンドボックスを狭めます。最初の変更は Products.CMFEditions 5.0.2 のモディファイアクラスにセキュリティ宣言を追加します。

 class ConditionalModifier(SimpleItem):
     """This is a wrapper for a modifier."""

+    security = ClassSecurityInfo()
+
     modifierEditForm = PageTemplateFile(
         "www/modifierEditForm.pt", globals(), __name__="modifierEditForm"
     )

+    @security.protected(ManagePortal)
     def edit(self, enabled=None, title="", REQUEST=None):
         """See IConditionalModifier."""

@security.protected(ManagePortal) は、Zope が edit を呼ぶ前に Manage portal 権限を確認することを意味します。匿名の訪問者は通りません。アクセサーには ViewManagementScreens が付き、サイズガードのフックは非公開になります。

2 番目の変更は、包括的な allow_module を明示的なリストに置き換えます。plone.batching 3.0.3 では次のとおりです。

-from AccessControl import allow_module
+from AccessControl import ModuleSecurityInfo
 from plone.batching.batch import Batch

-allow_module("plone.batching")
+# Only declare Batch public.  Do not use allow_module here: that would make
+# every name in this module available to restricted code, including
+# imported names like allow_class.
+ModuleSecurityInfo("plone.batching").declarePublic("Batch")
 allow_class(Batch)

Products.CMFPlone 6.2.3 は allow_module("Products.CMFPlone.utils") を ModuleSecurityInfo オブジェクトと公開名のリストに置き換えます。Products.MimetypesRegistry 4.0.2 は MimeTypeException だけを公開します。plone.restapi 10.2.1 は allow_module("json") を完全に削除します。サンドボックスはテンプレートとスクリプトが必要とする名前を引き続き公開しますが、それらの名前がインポートするモジュールは公開しません。

修正はベンダーが挙げた 5 つのパッケージに対して完全です。第三者のアドオンが自身のモジュールに allow_module を呼ぶと、サンドボックスを広げられる可能性があります。勧告はそうしたアドオンを対象にしていません。信頼できないコードを実行する場合は、アドオンに同じパターンがないか確認してください。

侵害されたかどうかを確認するには?

まず新しい条件チェッカーを使います。Manager として、サイトのルートで https://your-site/@@check-modifier-conditions を開きます。このページは既定値と異なる条件のモディファイアを一覧し、現在の値を示し、元に戻す選択肢を提示します。差分は手がかりであり、証明ではありません。既定値は時間とともに変わっており、管理者やアドオンが意図的に条件を設定している場合もあります。

Web サーバーのログでモディファイアツールへの要求を探します。Zope のアクイジションによりオブジェクトは任意の深さから到達でき、攻撃者はパスをエンコードできるため、パーセントエンコーディングをデコードし、大文字と小文字を区別せずに照合します。

grep -iE 'portal[_%]?modifier' /var/log/nginx/access.log
grep -iE 'portal(%5F|_)modifier' /var/log/apache2/access.log

マーカーを含む要求は開いて確認する価値があります。送信元アドレス、メソッド、応答コードが分かります。モディファイアオブジェクトへの edit 要求に対する 200 は、スキャナーの 404 より強い手がかりです。勧告は侵害の指標を公開しておらず、失敗した試行は要求行以外に痕跡を残さない場合があります。

チェッカーが自分で設定していない変更済みの条件を示した場合は、元に戻し、Zope プロセスが読めた秘密情報をローテーションし、サイトに変更されたコンテンツがないか確認します。コード実行が確認された場合は、サーバーを侵害済みとして扱い、正常なバックアップから再構築してください。コード実行はチェッカーが調べるファイルの外にバックドアを残す可能性があります。

年表

  • 2026-11-02: Plone が事前告知と portal_modifier のプロキシ回避策を公開します。
  • 2026-11-10 13:26 UTC: 修正済みパッケージと Products.PloneHotfix20261110 が PyPI にアップロードされます。
  • 2026-11-10 13:30 UTC: 公開勧告が 5 つの欠陥と修正バージョンを説明します。

事前告知から公開詳細までの 8 日間の年表
図 1: Plone は技術的詳細を公開する 8 日前に修正を告知しました。出典: Plone コミュニティの投稿、2026 年 11 月 11 日確認

よくある質問

CVE はありますか?

2026 年 11 月 11 日時点で CVE は割り当てられていません。5 つの勧告は GHSA 識別子で公開されており、告知は CVE 番号を要求したと述べています。CVE を待たずに GHSA の項目を追跡してください。

Plone 5 や Plone 4 も影響を受けますか?

はい。勧告は少なくとも Plone 4.3 までの旧版が影響を受けると述べています。Plone 5.2 以前はセキュリティサポートが終了しているため、これらのリリースでサポートされる方法はパッケージ更新ではなく修正パッケージです。

5 つのパッケージ更新はすべて必要ですか?

4 つの重大なパッケージと、インストールされている場合は plone.restapi を更新してください。告知は、plone.restapi を使っていなければ省略できると述べています。これは権限回避を広げる中程度の相棒であり、入口ではありません。残りの 4 つは勧告が説明する連鎖に必要です。

実際に悪用されていますか?

2026 年 11 月 11 日時点で悪用は確認されていません。ベンダーはリリース日に技術的詳細を公開し、事前告知では現在の AI ツールが説明から動作するエクスプロイトを短時間で作れる可能性があると警告していました。事前告知から更新までの期間を露出として扱ってください。

更新せずにプロキシ遮断を続けられますか?

プロキシ遮断はパスに portal_modifier を含む要求を止め、ベンダーは更新後も維持することを勧めています。別の経路が制限付きコードに到達した場合のサンドボックス脱出を修正せず、保存された条件を実行する内部の編集者経路も覆いません。暫定措置として使い、修正の代わりにしないでください。

修正パッケージは Python 2.7 で動作しますか?

はい。修正パッケージは Python 2.7 と Python 3 をサポートし、Plone 4.3、5.0、5.1、5.2、6.0、6.1、6.2 で動作します。

Ostorlab で公開された Plone サイトを見つける

Ostorlab の Web エージェント型ディープスキャンは、インターネットに公開された Plone サイト、到達可能なエンドポイント、公開されたコンポーネントを把握し、修正前にどのインスタンスが応答しているかを確認できます。インベントリ内のサイトに対して実行し、インターネットから到達できるものを優先するために結果を使ってください。

参考資料

  • Plone セキュリティ修正 20261110 の告知: https://community.plone.org/t/plone-security-hotfix-20261110/23313(2026 年 11 月 11 日確認)
  • 事前告知とプロキシ回避策: https://community.plone.org/t/pre-announcement-plone-security-fix-20261110/23303(2026 年 11 月 11 日確認)
  • Products.CMFEditions の勧告 GHSA-67qm-q795-jh7h: https://github.com/plone/Products.CMFEditions/security/advisories/GHSA-67qm-q795-jh7h(2026 年 11 月 11 日確認)
  • Products.CMFPlone の勧告 GHSA-92qw-564p-pmg6: https://github.com/plone/Products.CMFPlone/security/advisories/GHSA-92qw-564p-pmg6(2026 年 11 月 11 日確認)
  • Products.MimetypesRegistry の勧告 GHSA-xcj2-cmp9-fj62: https://github.com/plone/Products.MimetypesRegistry/security/advisories/GHSA-xcj2-cmp9-fj62(2026 年 11 月 11 日確認)
  • plone.batching の勧告 GHSA-6hcx-c235-cxh3: https://github.com/plone/plone.batching/security/advisories/GHSA-6hcx-c235-cxh3(2026 年 11 月 11 日確認)
  • plone.restapi の勧告 GHSA-vgxm-pwch-89q6: https://github.com/plone/plone.restapi/security/advisories/GHSA-vgxm-pwch-89q6(2026 年 11 月 11 日確認)
  • PyPI の Products.PloneHotfix20261110: https://pypi.org/project/Products.PloneHotfix20261110/(2026 年 11 月 11 日確認)
  • Products.CMFEditions 5.0.2 のソース: https://github.com/plone/Products.CMFEditions/blob/5.0.2/src/Products/CMFEditions/Modifiers.py(2026 年 11 月 11 日確認)
  • plone.batching 3.0.3 のソース: https://github.com/plone/plone.batching/blob/3.0.3/src/plone/batching/init.py(2026 年 11 月 11 日確認)
  • Products.CMFPlone 6.2.3 のソース: https://github.com/plone/Products.CMFPlone/blob/6.2.3/src/Products/CMFPlone/init.py(2026 年 11 月 11 日確認)
  • plone.restapi 10.2.1 のソース: https://github.com/plone/plone.restapi/blob/10.2.1/src/plone/restapi/init.py(2026 年 11 月 11 日確認)
  • Plone バックエンドコンテナの取得回数: https://hub.docker.com/r/plone/plone-backend(2026 年 11 月 11 日確認)