
एक निम्न-विशेषाधिकार वाला Docmost उपयोगकर्ता एक पीड़ित के attachmentId को सामान्य अपलोड एंडपॉइंट पर प्रदान करके उसी कार्यक्षेत्र में किसी अन्य पृष्ठ के संग्रहीत अटैचमेंट को अधिलेखित कर सकता है।
एक कम-विशेषाधिकार प्राप्त Docmost उपयोगकर्ता किसी पीड़ित के attachmentId को सामान्य अपलोड एंडपॉइंट पर प्रदान कर सकता था और उसी कार्यक्षेत्र में किसी अन्य पृष्ठ के संग्रहीत अनुलग्नक को अधिलेखित कर सकता था।
मैंने Docmost, ओपन-सोर्स सहयोगी दस्तावेज़ीकरण प्लेटफ़ॉर्म में एक उच्च-गंभीरता वाले प्राधिकरण दोष की पहचान की, जिम्मेदारी से खुलासा किया और इसे पुन: उत्पन्न किया।
Docmost की आधिकारिक साइट इसे 3M+ डाउनलोड वाला एक एंटरप्राइज़-रेडी ऑन-प्रिमाइसेस विकी बताती है, और कहती है कि विल्नियस सिटी, बेक्टल, ऑस्ट्रेलियाई सरकार, रेड क्रॉस और ETS क्यूबेक सहित संगठनों की टीमों द्वारा इस पर भरोसा किया जाता है।
बग Docmost द्वारा डायग्राम सेव/अपडेट फ़्लो में उपयोग किए जाने वाले सामान्य फ़ाइल-अपलोड पथ में रहता था।
मैं उस कोड की समीक्षा एक बहुत ही विशिष्ट प्रश्न के साथ कर रहा था:
क्या होता है यदि अपलोड एंडपॉइंट एक पृष्ठ पर संपादन पहुँच साबित करता है, लेकिन अधिलेखित लक्ष्य एक अलग उपयोगकर्ता-नियंत्रित अनुलग्नक आईडी के साथ चुना जाता है?
इस मामले में, उस प्रश्न ने सीधे एक वास्तविक ऑब्जेक्ट-बाइंडिंग विफलता का नेतृत्व किया।
Docmost ने कॉलर को भेजने की अनुमति दी:
pageId जिस पृष्ठ को वे संपादित करने की अनुमति रखते थे, औरattachmentId जो उसी कार्यक्षेत्र के एक अलग पृष्ठ से संबंधित थासर्वर ने एक अधिलेखित स्थिरता जाँच की, लेकिन गार्ड ने गलत बूलियन तर्क का उपयोग किया।
इसका मतलब था कि अनुरोध प्राधिकरण पास कर सकता था और फिर भी पीड़ित के अनुलग्नक को अधिलेखित कर सकता था।
यह मुद्दा CVE-2026-34213 बन गया।
Docmost: docmost/docmost
सलाहकार: GHSA-89fp-2hch-j9gp
CVE: CVE-2026-34213
पैच किया गया: v0.71.0 में
---
हमलावर-नियंत्रित pageId जिसमें संपादन पहुँच है -> हमलावर-नियंत्रित पीड़ित attachmentId -> दोषपूर्ण अधिलेखित गार्ड क्रॉस-पेज अधिलेखन को वैध मानता है -> पीड़ित attachmentId से भंडारण पथ पुनर्निर्मित -> हमलावर बाइट्स पीड़ित फ़ाइल को बदल देते हैं -> पीड़ित पृष्ठ संशोधित अनुलग्नक को परोसना जारी रखता है
Docmost पृष्ठ अनुलग्नकों को डेटाबेस रिकॉर्ड और भंडारण में बैकिंग फ़ाइलों के रूप में संग्रहीत करता है।
सामान्य अपलोड के लिए, सर्वर एक नई अनुलग्नक आईडी बनाता है और एक नई फ़ाइल लिखता है।
हालाँकि, डायग्राम सेव/अपडेट फ़्लो के लिए, क्लाइंट जानबूझकर एक मौजूदा attachmentId का पुन: उपयोग करता है ताकि हर बार एक नया अनुलग्नक रिकॉर्ड उत्पन्न करने के बजाय उसी डायग्राम फ़ाइल को स्थान पर अद्यतन किया जा सके।
यह व्यवहार अपने आप में वैध है।
समस्या यह है कि यह एक उच्च-जोखिम वाला पथ बनाता है:
जब भी कोई एंडपॉइंट इन दो जिम्मेदारियों को मिलाता है, तो कार्यान्वयन को उन्हें ठीक से एक साथ बाँधना चाहिए।
Docmost ने ऐसा नहीं किया।
मिश्रित क्रिएट/अपडेट एंडपॉइंट प्राधिकरण बग के लिए सामान्य स्थान हैं।
कारण सरल है:
यहाँ बिल्कुल यही पैटर्न है।
POST /api/files/upload ने मान्य किया कि कॉलर pageId द्वारा नामित पृष्ठ को संपादित कर सकता है।
लेकिन यदि attachmentId भी प्रदान किया गया था, तो सर्वर एक अधिलेखित पथ पर स्विच हो गया और एक मौजूदा अनुलग्नक रिकॉर्ड को अलग से चुना।
इसने महत्वपूर्ण सुरक्षा प्रश्न बनाया:
क्या अधिलेखित पथ यह साबित करता है कि चयनित अनुलग्नक वास्तव में अधिकृत पृष्ठ से संबंधित है?
कमजोर संस्करणों में उत्तर 'नहीं' था।
मूल कारण एक उपयोगकर्ता-नियंत्रित कुंजी के माध्यम से प्राधिकरण बाईपास था, जो अधिलेखित गार्ड में एक बूलियन तर्क बग के साथ संयुक्त था।
कमजोर फ़्लो इस तरह दिखता था:
AttachmentController.uploadFile() ने मल्टीपार्ट फॉर्म डेटा से pageId पढ़ा।validateCanEdit(page, user) को कॉल किया।attachmentId को अलग से स्वीकार किया।AttachmentService.uploadFile() ने हमलावर-प्रदत्त ID द्वारा मौजूदा अनुलग्नक को लोड किया।&& का उपयोग किया।कमजोर गार्ड था:
if (
existingAttachment.pageId !== pageId &&
existingAttachment.fileExt !== preparedFile.fileExtension &&
existingAttachment.workspaceId !== workspaceId
) {
throw new BadRequestException("File attachment does not match");
}
उस स्थिति ने केवल अनुरोध को अस्वीकार किया यदि:
एक साथ।
यह उसके विपरीत है जो एक अधिलेखित गार्ड को करना चाहिए।
वास्तविक हमले के मामले के लिए, हमलावर जानबूझकर उसी कार्यक्षेत्र के अंदर रहा।
इसलिए:
existingAttachment.workspaceId !== workspaceId false थाएक बार वह ऑपरेंड false हो गया, तो पूरी && शर्त false का मूल्यांकन करती है, भले ही अनुलग्नक किसी अलग पृष्ठ से संबंधित हो।
इसलिए सर्वर ने क्रॉस-पेज अधिलेखन को वैध माना।
यह बग का पहला भाग था।
दूसरा भाग वह है जिसने प्रभाव को वास्तविक बनाया।
जाँच के बाद, सेवा ने हमलावर-प्रदत्त attachmentId और फ़ाइलनाम का उपयोग करके गंतव्य भंडारण पथ को पुनर्निर्मित किया:
const filePath =
`${getAttachmentFolderPath(AttachmentType.File, workspaceId)}/` +
`${attachmentId}/${preparedFile.fileName}`;
फिर, अद्यतन पथ पर, Docmost ने केवल परिवर्तनीय मेटाडेटा को अद्यतन किया जैसे:
fileSizeupdatedAtइसने नहीं स्वामित्व को हमलावर पृष्ठ से पुन: बाँधा।
इसलिए पीड़ित पृष्ठ उसी अनुलग्नक रिकॉर्ड और उसी अनुलग्नक आईडी को इंगित करता रहा। केवल अंतर्निहित फ़ाइल बाइट्स बदल गए।
यही कारण है कि यह एक हानिरहित बेमेल नहीं था।
यह एक स्थायी अनधिकृत अधिलेखन प्रिमिटिव था।
यह एक कॉस्मेटिक बग नहीं था और फ़ाइलनाम टकराव का मुद्दा नहीं था।
हमलावर को रेस की आवश्यकता नहीं थी। हमलावर को यादृच्छिक पथ का अनुमान लगाने की आवश्यकता नहीं थी। हमलावर को पीड़ित पृष्ठ पर लिखने की पहुँच की आवश्यकता नहीं थी।
उन्हें केवल आवश्यकता थी:
वहाँ से, वे किसी अन्य पृष्ठ के अनुलग्नक के लिए संग्रहीत फ़ाइल बाइट्स को बदल सकते थे, जबकि पीड़ित पृष्ठ उस अनुलग्नक को संदर्भित और परोसता रहता था जैसे कि कुछ भी नहीं बदला हो।
यह एक सीधी अखंडता विफलता है।
व्यावहारिक रूप में, हमलावर कर सकता था:
महत्वपूर्ण बिंदु यह है:
सर्वर ने हमलावर द्वारा चुने गए अधिलेखित लक्ष्य को स्वीकार किया, बिना उसे उस पृष्ठ से बाँधे जिसकी संपादन अनुमति वास्तव में जाँची गई थी।
यह एक पहुँच-नियंत्रण विफलता है, न कि केवल खराब बूलियन स्वच्छता।
डायग्राम अनुलग्नकों के लिए शोषण विशेष रूप से व्यावहारिक था।
Docmost का क्लाइंट डायग्राम सेव के लिए जानबूझकर attachmentId का पुन: उपयोग करता है और नियतात्मक फ़ाइलनाम का उपयोग करता है:
diagram.excalidraw.svgdiagram.drawio.svgयह मायने रखता है क्योंकि यह हमलावर की आवश्यकताओं को कम करता है।
सामान्य अनुलग्नकों के लिए, हमलावर को दोनों की आवश्यकता होती है:
डायग्राम के लिए, फ़ाइलनाम पहले से ही अनुमानित है।
इसलिए यदि हमलावर पीड़ित पृष्ठ सामग्री पढ़ सकता है, तो वे अक्सर केवल एकमात्र लापता टुकड़ा प्राप्त कर सकते हैं:
attachmentIdअपने सत्यापन सेटअप में, मैंने ठीक उसी पथ का उपयोग किया:
यह पर्याप्त था।