TL;DR
Drupal SA-CONTRIB-2026-056によると、 AI AgentsのToolがContent Entityを読み込む際に、必要な権限を十分に確認していません でした。悪用には、影響を受けるToolがAgentで有効に設定され、攻撃者がそのAgentへ Accessできることが必要です。
影響範囲は1.1.4未満、1.2.0–1.2.4、1.3.0です。利用Branchに応じて1.1.4、1.2.5、
1.3.1へ更新してください。Drupalの公式アドバイザリは、Kuniyoshi Noguchi
(kuninogu)をReported ByとFixed Byの両方へ掲載しています。
JVN#20592637は本件を不適切な認可 (CWE-863)に分類し、利用者のPasswordを取得され、Accountを乗っ取られる可能性が あると説明しています。Field単位の出力制御は、表示やPrivacyだけでなくSecurity Boundary です。
調査理由 / なぜ重要か
AI AgentはApplication dataへの間接経路を追加します。
user -> agent -> selected tool -> entity loader -> fields -> model/user output利用者がAgentを開く権限を持っていても、特定Entityや機密Fieldを読む権限を持つとは 限りません。同様に、Agentが多数のToolを提供できても、実際に利用を許可されたToolは 一部かもしれません。「Agentを使える」を、そのToolから到達できるすべてへの包括的な 認可として扱うと、AgentがConfused Deputyになります。
これはDrupal以外でも重要です。Agent systemは、以前はUI RouteやAPIへ分割されていた Capabilityを集約します。各Tool invocationは実行主体を維持し、Data access時と出力整形時に 対象Application本来のAuthorizationを再適用する必要があります。
Trust Boundary
少なくとも四つの独立した判断があります。
- Agent access: この主体はAgentと対話できるか。
- Tool access: このAgentは対象Toolを呼び出せるか。
- Entity access: 実行主体は対象Entityを閲覧できるか。
- Field access: 実行主体はTool結果へ含める各Fieldを閲覧できるか。
Agent/Tool requestがDrupal Entity loadへ変換され、その後Serialized resultになる箇所で Trust Boundaryを越えます。元のPrincipalの権限をその処理へ維持しなければなりません。 Entityを読み込めたことは、全Fieldを返してよい証明ではありません。UIでFieldを隠す こともAuthorization checkにはなりません。
公開アドバイザリは、正確なTool名、Route、Prompt、Method、Patch hunkを特定していません。 したがって本記事は、確認済みのAuthorization classと防御上のInvariantを説明し、Exploit pathを推測して補いません。
根本原因
Drupalが公開したRoot causeの説明は簡潔です。ToolがContent Entityを読み込む際に、Moduleが 必要なPermissionを十分に確認していませんでした。JVNはCWE-863(不適切な認可)として います。
少なくともContent load pathで、返却Dataに必要なAccess decisionのすべてを維持・適用できて いませんでした。JVNがPassword disclosureの可能性を示しているため、完全なRegression strategyにはEntity全体だけでなく、機密Field accessのTestが必要です。
誤った認可の含意は次のように表せます。
can_use_agent = true
does NOT imply can_use_every_tool
does NOT imply can_view_every_entity
does NOT imply can_view_every_field実装上のErrorがEntity check不足、Field check不足、誤ったActing account、またはその組合せ だったかは、参照した公開アドバイザリに関数レベルで記載されていません。本記事でも、 それ以上に狭いCode-levelの原因を断定しません。
Safe reproducer
Synthetic dataを用いたLocalまたは隔離済みDrupal環境だけで実施します。実在利用者の Passwordを使ったり、Production AgentへSecretの取得を指示したりしてはいけません。
- 環境のBranchに対応する修正版1.1.4、1.2.5、1.3.1のいずれかを導入する。
- Test userが明示的に閲覧を拒否されるFieldへ
CANARY-NOT-A-REAL-SECRET等を入れた Synthetic EntityまたはTest accountを作る。 - Test Agentは利用できるが、通常のDrupal経路では保護EntityまたはFieldを閲覧できない 最小権限Userを作る。
- Agentでは必要なTest Toolだけを有効にし、Synthetic recordだけを対象に呼び出す。
- Toolが処理を拒否するか保護Fieldを除外し、CanaryがModel context・出力へ入らず、拒否が Logへ記録されることを確認する。
- 不足Permissionを付与して再実行する。認可後は値が返ることを確認し、Toolの故障ではなく Authorizationを検証できたことを示す。
- LabのRetention policyに従い、Synthetic record、Conversation、Test accountを削除する。
この方法なら製品固有Prompt、Route、実在Secretを公開せず、修正版のSecurity propertyを 検証できます。過去のExposureは、旧ProductionをExploitするのではなくVersion inventoryで 判断します。
修正差分の評価
Moduleには複数の対応Branchがあるため、Drupalは1.1.4、1.2.5、1.3.1の三つを修正版として 掲載しています。公開アドバイザリはReporterを含む複数のFix contributorを掲載していますが、 行単位のSecurity patch解説は公開していません。そのため、観測可能なAuthorization結果を 中心に評価します。
完全な修正では、次を満たす必要があります。
- Default・Ambient・特権Service identityではなく、実際のActing principalでAccessを評価する。
- Agentで利用を設定していないToolを拒否する。
- Contentを読み込み・Serializeする前にEntity accessを強制する。
- Computed fieldやReference先を含む、返却する各FieldのAccessを強制する。
- Authorization/cache metadataを結果へ維持し、あるUser向け結果が別Userへ再利用されない。
- IdentityまたはAccess情報が欠ける場合はfail closedにする。
- 拒否した値を最終Chat responseだけでなく、Model context、Log、Trace、Error messageにも 含めない。
最後の点は重要です。SecretがModel promptへ入った後で表示回答だけをFilterしても、Model providerやObservability pipelineへのDisclosureは取り消せません。
回帰テスト
「Administrator」と「Anonymous」だけでなく、Authorization matrixを使います。
| 主体の状態 | Agent | Tool | Entity | 機密Field | 期待結果 |
|---|---|---|---|---|---|
| Agent権限なし | Deny | Any | Any | Any | Tool callなし |
| Agent許可 | Allow | Disabled | Any | Any | Tool選択・実行を拒否 |
| Agent・Tool許可 | Allow | Allow | Deny | Any | Entityを読込・返却しない |
| Entity許可、Field拒否 | Allow | Allow | Allow | Deny | Fieldを除外し、拒否を記録 |
| 全Permission許可 | Allow | Allow | Allow | Allow | 認可済みDataを返却 |
| Queue/Background runでIdentity不明 | Unknown | Any | Any | Any | Fail closed |
Reference entity、Revision、Translation、Computed field、Cached responseでもMatrixを繰り返し ます。すべての拒否CaseでCanaryがLLM request body、Tracing system、Exception log、Conversation historyに存在しないこともAssertします。
Detection
必要なTelemetry
Tool callごとにCorrelation/Run ID、Acting user ID、Agent ID、Tool ID、Entity type/ID、要求Field、 返却Field、Entity/FieldのAuthorization結果を記録します。Field valueやSecretを含むPromptは 記録しません。Drupalの標準LogだけではContextが不足する場合があるため、Tool Boundaryで 明示的なAudit eventが必要です。
Signal強度の高いInvariantは次です。
returned_fields INTERSECT denied_fields MUST equal empty_setAudit eventで件数を正規化している場合、次の例示SPLで違反を検索できます。IndexとField名は 実装済みSchemaへ置き換えてください。
index=YOUR_DRUPAL_INDEX event_type=ai_agent_tool_result
| where returned_field_count > 0 AND denied_field_count > 0
| stats count values(entity_type) as entity_types
values(tool_id) as tools values(run_id) as run_ids
by user_id agent_id
| sort - countAccount/User entityへのAccess、一つのAgent sessionからの大量Entity read、同じUserが通常Route では到達できないTool実行、Model gateway・DLP telemetry内の機密Canary IDも調べます。上記 QueryはApplicationがAuthorization-aware eventを出力した後に有効な例であり、Drupal Defaultの Field名を示すものではありません。
Incident Response
- Logと設定を保全しながら、影響Toolを無効化するか影響AgentへのAccessを制限する。
- 全Drupal instanceのModule versionとAgent-to-Tool設定を記録する。
- Drupal log、Agent conversation、Tool-call audit event、Model gateway metadata、Reverse-proxy log、関連Database audit recordを保全する。
- Exposure windowを特定し、関係したPrincipal、Agent、Tool、Entity、Fieldを列挙する。記録が 許す範囲で、各Readを当時のPrincipalのAuthorizationと照合する。
- JVNがPassword disclosureの可能性を示しているため、返却された可能性のあるCredentialを 強制Reset/Rotationし、Sessionを失効して、その後のAccount activityを調査する。他のSecretも Scopeに応じてRotationする。
- 対応Branchの修正版へ更新し、Authorization-sensitive cacheを無効化して、Tool再有効化前に Regression matrixを実行する。
- 外部Model・Tracing providerへ送られたDataを確認し、契約上必要な通知・削除手続を行う。
機密Tool outputをIncident ticketへ複製しないでください。Raw valueが不要な場合は、Hash、ID、 Access metadataを保全します。
Disclosure Timeline
- 報告日: 参照した公開アドバイザリには記載されていません。
- 2026-06-24: DrupalがSA-CONTRIB-2026-056を公開し、1.1.4、1.2.5、1.3.1を修正版として
掲載。Kuniyoshi Noguchi(
kuninogu)をReporter・Fix contributorの両方へ掲載。 - 2026-07-21: JVNがJVN#20592637を公開し、開発者とIPAへの報告者としてKuniyoshi
Noguchi(
@KuniNogu)を掲載。 - 非公開の調整・Patch review日: 参照した公開アドバイザリには記載されていません。