
React Server Components संस्करण 19.0.0, 19.1.0, 19.1.1 और 19.2.0 में Pre-auth RCE।
इस रिपॉजिटरी में CVE-2025-55182 का एक PoC प्रजनन (reproduction) है, जो React Server Components (RSC) में एक गंभीर सुरक्षा भेद्यता है जो बिना प्रमाणीकरण के मनमाना कोड निष्पादन (arbitrary code execution) की अनुमति देता है।
यह भेद्यता इस बात में मौजूद है कि React Server Components क्लाइंट अनुरोधों से "Server Actions" को कैसे डी-सीरियलाइज़ (deserialize) करते हैं। विशेष रूप से, requireModule फ़ंक्शन यह सत्यापित करने में विफल रहा कि अनुरोधित एक्सपोर्ट नाम मॉड्यूल का सीधा प्रॉप (direct prop) था। इससे हमलावर एक्सपोर्ट किए गए फ़ंक्शंस के constructor प्रॉप तक पहुँच सकते थे, जिससे वैश्विक Function कंस्ट्रक्टर का संदर्भ प्राप्त होता है, जिसका उपयोग मनमाना कोड निष्पादित करने के लिए किया जा सकता है।
यह PoC react-server-dom-webpack लाइब्रेरी में भेद्यता को अलग करने के लिए न्यूनतम Node.js वातावरण का उपयोग करता है, ताकि यह सुनिश्चित किया जा सके कि एक्सप्लॉइट लाइब्रेरी में ही बग को प्रदर्शित करता है, न कि किसी फ्रेमवर्क में गलत कॉन्फ़िगरेशन को।
npmnpm install
[!NOTE]
package.jsonभेद्य संस्करण19.0.0पर पिन किया गया है।
यह स्क्रिप्ट एक रॉ HTTP सर्वर स्थापित करती है जो अनुरोधों को डिकोड करने के लिए भेद्य React रनटाइम का उपयोग करता है।
# tty1
node --conditions react-server server.js
एक अलग टर्मिनल में, एक्सप्लॉइट चलाएँ। यह सर्वर पर एक दुर्भावनापूर्ण Flight पेलोड भेजता है।
# tty2
node exploit.js id
आपको कमांड आउटपुट प्रतिक्रिया में लौटा हुआ देखना चाहिए:
अपेक्षित आउटपुट:
Response: uid=0(root) gid=0(root) groups=0(root)
भेद्यता क्यों हुई?
ReactFlightDOMServerNode.js में requireModule फ़ंक्शन ने मूल रूप से क्लाइंट द्वारा भेजे गए किसी भी name पर भरोसा किया। उसने यह जाँचे बिना कि वह प्रॉपर्टी वास्तव में एक्सपोज़ होने के लिए थी या नहीं, moduleExports[metadata[NAME]] कर दिया। इसलिए यदि क्लाइंट कहता है "भाई, मुझे यह प्रॉपर्टी चाहिए", तो सर्वर बस कहता है "ज़रूर! ले लो, दोस्त"।
लोगों को किसी भी प्रॉपर्टी तक पहुँच देना बुरा विचार क्यों है?
क्योंकि यह मूल रूप से किसी को भी प्रोटोटाइप चेन में पहुँचने देता है, यहाँ तक कि constructor तक भी, जो अत्यंत खतरनाक है। यदि मॉड्यूल एक फ़ंक्शन एक्सपोर्ट करता है (जैसे module.exports = () => {}), तो उसका constructor शाब्दिक रूप से वैश्विक Function कंस्ट्रक्टर होता है।
Function कंस्ट्रक्टर प्राप्त करने का अर्थ RCE क्यों है?
एक बार हमलावर Function कंस्ट्रक्टर प्राप्त कर लेता है, तो वे "Bound Server Action" सुविधा का दुरुपयोग कर सकते हैं। वे दुर्भावनापूर्ण JavaScript युक्त एक स्ट्रिंग को उससे बाँध देते हैं (मूल रूप से इसे new Function("evil code") में बदल देते हैं)। और एक बार यह चलने पर, सर्वर उनके डाले गए किसी भी कोड को निष्पादित करता है।
React उस दुर्भावनापूर्ण फ़ंक्शन को वास्तव में क्यों चलाएगा?
क्योंकि Server Actions को ID द्वारा ट्रिगर किया जा सकता है। यदि हमलावर एक Action ID के साथ पेलोड तैयार करता है जो उनके module#constructor संदर्भ को इंगित करता है, तो React इसे एक सामान्य एक्शन की तरह हल करता है और निष्पादित करता है। वह "एक्शन" वास्तव में उनका दुर्भावनापूर्ण फ़ंक्शन होता है।
इनमें से किसी को भी मान्य क्यों नहीं किया गया?
सिस्टम ने बस यह मान लिया कि Server Reference मेटाडेटा से id और name हमेशा डेवलपर द्वारा परिभाषित मान्य एक्सपोर्ट को संदर्भित करेंगे। यह सुनिश्चित करने के लिए कोई सुरक्षा जाँच नहीं थी जैसे hasOwnProperty कि अनुरोधित प्रॉप वास्तव में एक वास्तविक एक्सपोर्ट है न कि प्रोटोटाइप चेन से विरासत में मिली कोई चीज़।
server.js क्यों?मैं React Server Components रनटाइम को मैन्युअल रूप से कॉन्फ़िगर करने के लिए एक रॉ server.js (और एक सहायक webpack-runtime.js) का उपयोग करता हूँ। यह हमें अनुमति देता है:
module.exports = fn)s। एक वास्तविक बंडलर अपने कॉन्फ़िगरेशन के आधार पर एक्सपोर्ट के लपेटे जाने के तरीके को बदल सकता है।react-server-dom-webpack के अंदर है, Next.js में नहीं।react-server-dom-webpack मानता है कि यह Webpack बंडल के अंदर चल रहा है। हमारा webpack-runtime.js इसे वे globals प्रदान करता है जिनकी यह अपेक्षा करता है (__webpack_require__, __webpack_chunk_load__)।
यह भेद्यता का मज़ाक नहीं है, यह केवल लाइब्रेरी को वह न्यूनतम रनटाइम दे रहा है जिसकी उसे वास्तव में काम करने के लिए आवश्यकता है।"Invalid PoCs" के बारे में चर्चा हुई है जो केवल तभी काम करते हैं जब डेवलपर जानबूझकर खतरनाक चीज़ें जैसे child_process.exec उजागर करता है।
यह PoC उनमें से एक नहीं है। यह एक सामान्य, सुरक्षित सेटअप पर काम करता है।
एक्सपोज़ किया गया फ़ंक्शन हानिरहित है
ऐप एक साधारण updateProfile फ़ंक्शन एक्सपोज़ करता है जो केवल एक स्ट्रिंग लौटाता है और कुछ भी संदिग्ध नहीं, कोई शेल कमांड नहीं।
एक्सप्लॉइट उस फ़ंक्शन से पूरी तरह बाहर निकल जाता है
भेद्यता हमलावर को सुरक्षित एक्सपोर्ट को अनदेखा करने और सीधे updateProfile.constructor पर कूदने देती है, जो वैश्विक Function कंस्ट्रक्टर है।
मुख्य मुद्दा प्रॉपर्टी एक्सेस है
React को .constructor तक पहुँच की अनुमति नहीं देनी चाहिए थी। डेवलपर ने Function कंस्ट्रक्टर को एक्सपोज़ करने का इरादा नहीं किया था, इसके बजाय, असुरक्षित डी-सीरियलाइज़ेशन ने उनके लिए ऐसा किया।
एकमात्र वास्तविक आवश्यकता यह है कि मॉड्यूल सीधे एक फ़ंक्शन एक्सपोर्ट करता है (module.exports = fn), जो CommonJS और कई बंडलर सेटअपों में बहुत सामान्य है।
exploit.js में पेलोड तीन चंक्स के साथ एक React Flight संदेश तैयार करता है:
id: "user-profile-action#constructor", जिसका अर्थ है "मुझे कंस्ट्रक्टर दो"।bound: चंक 2 को इंगित करता है, जिसमें तर्क होते हैं।["console.log('nice try, diddy!')"]: दुर्भावनापूर्ण कोड स्ट्रिंग।जब React इसे डी-सीरियलाइज़ करता है:
user-profile-action को हल करता है।.constructor प्रॉपर्टी पढ़ता है => वैश्विक Function प्राप्त करता है।new Function("console.log('nice try, diddy!')")और यही RCE है!
तुरंत पैच किए गए संस्करणों में अपग्रेड करें:
react-server-dom-webpack >= 19.0.1react-server-dom-parcel >= 19.0.1react-server-dom-turbopack >= 19.0.1पैच विरासत में मिली प्रॉपर्टीज़ तक पहुँच को रोकने के लिए hasOwnProperty जाँच प्रस्तुत करता है और base64 फ़ाइल अपलोड को प्रतिबंधित करता है।
यदि आप इस PoC को पैच किए गए संस्करण के विरुद्ध चलाते हैं, तो सर्वर क्रैश हो जाएगा या त्रुटि देगा:
$ node --conditions react-server server.js
Listening on http://localhost:3000
/path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726
resolvedValue = resolvedValue.bind.apply(
^
TypeError: Cannot read properties of undefined (reading 'bind')
at /path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726:43
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Node.js v20.19.3
यह पुष्टि करता है कि एक्सप्लॉइट constructor प्रॉपर्टी तक पहुँचने में विफल रहा (यह Function के बजाय undefined लौटा), और इस प्रकार बाद की .bind कॉल विफल हो गई।
यह कोड केवल शैक्षिक और परीक्षण उद्देश्यों के लिए है। इस एक्सप्लॉइट का उपयोग उन प्रणालियों के विरुद्ध न करें जिनके आप स्वामी नहीं हैं या जिनके परीक्षण के लिए आपके पास स्पष्ट अनुमति नहीं है।
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE के अंतर्गत जारी किया गया।