この記事のポイント
- 脆弱性
- CVE-2026-115635
- 深刻度
MEDIUM6.0
- 対象
- ash_postgres 2.6.22以上2.15.2未満(属性によるテナント分離とスキップしたupsertの結果返却を利用)
- 悪用状況
- 不明
- 推奨対応
- ash_postgresを2.15.2へ更新して再配備する。単一と一括の作成でスキップ時の返却行の所属を試験し、過去の返却データと後続処理を調査する。
- 公表日
目次
ElixirのAshでPostgreSQLを利用するash_postgresに、別のレコードが返る不備-2026-115635が公表されました。対象は2.6.22以上2.15.2未満で、修正版は2.15.2です。属性で顧客データを分け、upsertがスキップされた場合も既存レコードを返す構成の担当者は、依存パッケージを更新し、返却データの所属まで検証してください。
2026年10月25日公開の開発元のセキュリティ勧告を基に、10月26日に確認したニュースと対処の解説です。問題はデータを書き換える処理だけにありません。「更新しなかったので安全」と判断した後の読み戻しにも、テナントの境界が必要です。本稿の試験・調査手順は運用提案であり、本サイトが攻撃を再現して測定した結果ではありません。
スポンサーリンク
対象は属性分離とスキップ結果の返却が重なる構成
Ashはリソースやアクションを定義してデータを扱うElixirのフレームワークで、AshPostgresはPostgreSQL向けのデータ層です。今回更新するパッケージ名はash_postgresです。PostgreSQLサーバー本体の版を上げただけで、このライブラリーの修正を取り込んだとは判断できません。
公式勧告の条件は、リソースが属性によるマルチテナンシーを使うこと、アクションがreturn_skipped_upsert?: trueを指定してupsertを行うこと、呼び出し側が別テナントでも使われるidentityの値を指定できることです。upsert_conditionが成立しないなどの理由で更新がスキップされると、既存行を探す読み戻しで別テナントの行が候補になります。
本サイトでは、利用版、分離方式、アクションの設定、入力経路を一組で確認することを勧めます。の取込、同期処理、管理用の一括登録などは調査先の例です。これらすべてで問題が起きるという意味ではなく、コード上の条件と実際に外部から指定できる値を照合するための棚卸しです。
同じ識別値を使えること自体は不具合ではない
Ash公式のマルチテナンシー資料は、:attributeと:contextの二つの方式を区別しています。属性方式では、organization_idなどの属性に対応するtenantで行を絞ります。AshPostgresのコンテキスト方式はPostgreSQLのを使う方式です。今回の勧告が明示するのはstrategy :attributeであり、方式の違いを無視して全構成が同じ条件だと説明しないでください。
公式資料では、テナントを考慮するidentityの一意性はテナント内で保たれ、異なるテナントで同じidentity値を使えます。たとえば各顧客が同じ外部商品コードを使える設計は自然です。全テナントで同じ値を禁止するall_tenants?の設定もありますが、今回の対応として業務上の一意性を無計画に変更することは勧めません。
仮想例として、顧客AとBに同じ連携コードがある状況を考えます。Aの操作で更新が見送られた後、「元のレコードを返す」ための検索がコードだけを条件にすると、Bのデータが返る可能性があります。必要なのは、書き込み条件と同じ顧客範囲を返却用の検索にも引き継ぐことです。この例は理解のためのモデルで、特定サービスの被害を示すものではありません。
スポンサーリンク
書き込みの成功と返却の安全性を別に見る
AshのアクションAPI資料によると、return_skipped_upsert?は、フィルターによりupsertしなかったときに元のレコードを返すためのオプションで、既定値はfalseです。upsert_identityは競合の判定に使うidentity、upsert_conditionは競合時に更新するかを判断する式です。単にupsertを利用しているというだけでは、今回の条件がそろったことにはなりません。
ここから得られる設計上の教訓は、更新の可否と読み取りの可否を分けることです。DB上の行が変化していなくても、レスポンス、画面表示、後続ジョブへ別顧客の値が渡れば、機密性の問題になります。更新件数がゼロだったことを、情報が一切出なかったという判定へ使わないようにします。
勧告の v4.0は6.0、深刻度はModerateです。攻撃条件には低い権限が必要とされ、主な影響は機密性に示されています。認証不要の任意コード実行や、全体の改ざんが確認された問題として扱いません。また、確認した勧告から実環境での悪用を確定することはできず、悪用中とも未悪用とも断定しません。
修正は読み戻しへテナントの絞り込みを追加
開発元の修正コミットでは、テナントを設定したクエリからデータ層のクエリへ変換する前に、属性のテナント条件を適用する処理が加わっています。一括作成と単一のupsertの両方に関係する変更です。アプリでtenantを渡していることだけをもって、内部のすべての読取経路に条件が効くと推定できない点が重要です。
同コミットには、二つの組織で同じリンク情報を作り、条件をfalseとしてupsertをスキップさせた後、呼び出し側のテナントのレコードが返ることを確かめる回帰テストもあります。これは開発元の試験です。自社では、単一と一括の入口、レスポンスへ渡すフィールド、業務上の権限を加えて確認する必要があります。
スポンサーリンク
最初に更新と到達経路の制限を進める
優先対応はash_postgresを2.15.2へ更新し、修正を含むでアプリを作り直して配備することです。の依存指定と、成果物、稼働するWeb・ジョブの実体を照合します。開発端末だけの更新や、変更をコミットしただけの状態を完了にしないでください。
すぐ配備できない場合は、該当アクションを一時停止する、外部から呼べる対象を限定するなど、問題の条件へ到達させない措置を検討します。これは本サイトの提案です。返却オプションを無効にする場合も、呼び出し側が既存レコードを必要としていないかを調べ、戻り値の変更を試験してください。公式修正を取り込む代わりの恒久対応とは扱いません。
検索キーを推測しにくくするだけでは、顧客間の分離を保証できません。利用者が通常業務で知る値が重なることもあります。テナントの値は済み利用者の所属と照合し、リクエスト本文に書かれたorganization_idをそのまま権限の証明にしない設計も確認します。後者は一般的な認可点検であり、今回の欠陥がアプリ側の設定ミスだけだったという説明ではありません。
検証は二つの顧客と重複する値で組み立てる
試験には実顧客の情報を使わず、隔離した環境にA・Bの二つのテナントを作ります。同じidentity値と、所属を見分けられる無害な項目を用意してください。正常に登録できる試験だけでは、スキップ後の読取経路を通らないため、今回の問題の回帰確認として不足します。
第一にAから通常の作成とupsertを行い、Aのデータだけが返ることを確認します。第二に、業務で利用する条件に沿ってupsertを意図的にスキップさせ、返却レコードの所属とフィールドを確かめます。第三にAとBを入れ替えて実行し、データの作成順が違う場合も同じ境界が保たれるか確認します。
一括処理では、複数の入力に成功・スキップ・エラーが混じるケースを含めます。件数だけで合格にせず、それぞれの返却行がどの入力とテナントに対応するかを照合してください。単一作成の入口も別に試し、一括側だけが通った結果をすべてのAPIへ広げないことが大切です。
自社の設計によっては、該当テナントに返せる行がない場合があります。そのときのエラーや空の結果を、呼び出し側が正しく扱うかも試験します。処理失敗を回避するためにテナント条件を外した検索へしていれば、ライブラリー更新後にも独自の境界違反が残り得ます。
過去の調査はレスポンスと後続処理まで
影響する構成を本番で使っていた場合、公開期間、呼べたアクション、指定可能なidentity、返却した項目を整理します。更新をスキップした記録と、その直後に読み戻した行の所属を関連付けられるか調べてください。DBの更新監査だけでは、読取による露出を把握できない場合があります。
ただし、調査のためにレスポンス全文やを新たに大量保存することは避けます。操作ID、時刻、利用者、要求側と返却側のテナント識別子など、照合に必要な情報を適切な権限で扱います。既存ログで返却内容を復元できない期間は「漏えいなし」と結論せず、確認範囲の限界として残します。
別テナントの値が後続の、検索索引、通知、外部連携へ渡る構成なら、その保存先も調査対象です。これは実際のデータフローに応じた提案で、今回のCVEで全種類の二次被害が観測されたという意味ではありません。自社で露出を確認した場合は、対象項目と期間を確定し、対応の担当へつなぎます。
完了条件は、修正版を稼働環境へ適用したこと、条件に該当する入口を棚卸ししたこと、スキップ時も別テナントのデータを返さない試験を通したことです。今回の修正を機に、作成・更新の許可だけでなく、失敗・競合・再読込を含む戻り値まで顧客の境界を確認してください。
配備票には、Webプロセスだけでなく非同期ワーカーの再起動と、古い成果物を使う定期ジョブの確認を含めます。更新中に旧版と新版が混在する場合は、その時間帯の対象経路を制限し、全インスタンスが入れ替わった時点を記録してください。検証用データで得た結果と、本番ログから確認できる範囲を混ぜず、試験の合格、過去の露出調査、サービスの復旧を別々の完了項目として管理すると、担当が分かれていても確認漏れを減らせます。
10月26日追記:Ash本体のupsertも別途確認する
同日公表のAsh本体の公式勧告CVE-2026-96581では、ash 1.22.0以上3.37.2未満に、属性によるテナント分離を無視して別テナントの行を読み取り・更新し、所属まで変更できる問題が示されました。修正版はash 3.37.2です。本稿のash_postgres 2.15.2への更新とは対象パッケージが異なるため、両方の依存版を照合してください。
条件は、属性分離のリソースでupsert? trueの作成アクションを公開し、主キーを受け付けて主キーで競合判定するか、all_tenants?のidentityを使い、呼び出し側が別テナントのキーを知るか列挙できる場合です。通常の読み取り・更新ポリシーだけで防げるとは判断しないでください。公式の暫定策は該当する各アクションへupsert_condition expr(<tenant attribute> == ^tenant())を追加することですが、return_skipped_upsert?と組み合わせない条件があります。また、影響版のMnesiaデータ層はupsert条件を無視するため、この暫定策は使えません。修正適用を優先し、返却行の所属に加えて別テナントの行が変更されないことも検証してください。これは関連する影響条件・修正先の追記で、CVE-2026-115635自体の深刻度や影響範囲を変更するものではありません。
出典・一次情報
本記事は以下の公開情報をもとに作成しています。最新の状況は各リンク先で確認してください。
-
公式アドバイザリ
-
公式アドバイザリ
-
公式アドバイザリ
-
公式アドバイザリ













