
पेज ट्री में एक public share साफ दिखता था, लेकिन search endpoint ने एक अलग कहानी बताई। Docmost में, public share देखने वालों से छिपाए गए restricted child pages अभी भी public share search results के माध्यम से लीक हो सकते हैं।
पेज ट्री में एक सार्वजनिक शेयर साफ दिखता था, लेकिन सर्च एंडपॉइंट ने कुछ और ही कहानी सुनाई। Docmost में, सार्वजनिक शेयर देखने वालों से छिपाए गए प्रतिबंधित चाइल्ड पेज, सार्वजनिक शेयर सर्च परिणामों के माध्यम से लीक हो सकते हैं।
मुझे यह समस्या Docmost की समीक्षा करते समय मिली, जो एक ओपन-सोर्स सहयोगी विकी और डॉक्यूमेंटेशन प्लेटफ़ॉर्म है, और मेरे मन में एक बहुत ही सरल प्रश्न था:
यदि कोई पेज जानबूझकर सार्वजनिक शेयर देखने वाले से छिपाया गया है, तो क्या हर सार्वजनिक सुविधा उसी प्रतिबंध सीमा का सम्मान करती है?
इस मामले में, उत्तर नहीं था।
एक प्रतिबंधित चाइल्ड पेज सार्वजनिक शेयर ट्री में छिपा रह सकता था, जबकि सार्वजनिक शेयर सर्च एंडपॉइंट के माध्यम से लीक हो रहा था।
समस्या स्वीकार की गई और CVE-2026-33146 असाइन की गई।
Docmost: GitHub पर Docmost
CVE: CVE-2026-33146
Docmost की आधिकारिक साइट इसे 3M+ डाउनलोड वाली एंटरप्राइज़-रेडी ऑन-प्रिमाइसेस विकी के रूप में प्रस्तुत करती है, और कहती है कि इस पर विल्नियस शहर, बेक्टल, ऑस्ट्रेलियाई सरकार, रेड क्रॉस और ETS क्यूबेक सहित संगठनों की टीमें भरोसा करती हैं।
सार्वजनिक पैरेंट शेयर जिसमें सबपेज सक्षम हैं → प्रतिबंधित वंशज सार्वजनिक ट्री से हटा दिया गया → हमलावर सार्वजनिक शेयर सर्च करता है → प्रतिबंधित चाइल्ड का शीर्षक और स्निपेट लीक
Docmost एक सहयोगी विकी और डॉक्यूमेंटेशन प्लेटफ़ॉर्म है।
यह प्रदान करता है:
इसका मतलब है कि इसका सार्वजनिक-शेयरिंग मॉडल एक वास्तविक सुरक्षा सीमा है।
यहाँ महत्वपूर्ण प्रश्न यह नहीं था कि क्या Docmost पेजों को सार्वजनिक रूप से साझा कर सकता है।
असली प्रश्न था:
जब Docmost यह निर्णय लेता है कि कोई वंशज पेज प्रतिबंधित है और उसे सार्वजनिक शेयर आगंतुक को नहीं दिखना चाहिए, तो क्या वह प्रतिबंध सार्वजनिक शेयर प्रवाह में हर जगह लागू होता है?
इस मामले में, यह नहीं हुआ।
बहुत सारी सुरक्षा समीक्षाएँ बहुत जल्दी रुक जाती हैं जब वे UI में एक पेज छिपा हुआ देखते हैं।
यह पर्याप्त नहीं है।
अधिक मजबूत प्रश्न यह है:
क्या हर बैकएंड पथ उसी दृश्यता निर्णय को लागू करता है?
यह मायने रखता है क्योंकि सुरक्षा सीमाएँ इंटरफ़ेस के दिखने से परिभाषित नहीं होतीं। वे सर्वर द्वारा वास्तव में क्या लौटाया जाता है, इससे परिभाषित होती हैं।
यहाँ, सार्वजनिक ट्री एंडपॉइंट सुरक्षित रूप से व्यवहार करता था:
लेकिन सार्वजनिक शेयर सर्च पथ अलग व्यवहार करता था:
इसने इसे एक वास्तविक प्राधिकरण और सूचना प्रकटीकरण समस्या बना दिया, न कि केवल एक प्रस्तुति विसंगति।
मैंने Docmost तक बेतरतीब ढंग से रूट्स को फ़ज़ करके और उम्मीद करके नहीं पहुँचा कि कुछ दिलचस्प दिखाई दे।
अधिक मजबूत तरीका यह था कि पहले एक विश्वास सीमा चुनी जाए।
उन अनुप्रयोगों के लिए जो समर्थन करते हैं:
पूछने के लिए सबसे अच्छे प्रश्नों में से एक है:
क्या सर्च लेयर ब्राउज़ लेयर के समान प्राधिकरण सीमा को लागू करती है?
यह प्रश्न विशेष रूप से मूल्यवान हो जाता है जब:
यह ठीक वहीं है जहाँ यह समस्या दिखाई दी।
बग यह नहीं था कि Docmost सामान्य सार्वजनिक ट्री में प्रतिबंधित पेज को छिपाने में विफल रहा।
बग यह था कि सार्वजनिक सर्च ने उसी प्रतिबंध तर्क का सम्मान नहीं किया।
स्रोत समीक्षा से, सार्वजनिक ट्री फ़्लो प्रतिबंध-जागरूक वंशज ट्रैवर्सल का उपयोग करता था।
प्रासंगिक क्षेत्र:
apps/server/src/core/share/share.service.tsउस पथ ने जानबूझकर प्रतिबंधित वंशजों को इसका उपयोग करके बाहर रखा:
getPageAndDescendantsExcludingRestricted(...)लेकिन सार्वजनिक शेयर सर्च फ़्लो एक अलग पथ का अनुसरण करता था।
प्रासंगिक क्षेत्र:
apps/server/src/core/search/search.controller.tsapps/server/src/core/search/search.service.tsवहाँ, कोड ने इसका उपयोग करके वंशज एकत्र किए:
getPageAndDescendants(...)इसका मतलब था कि प्रतिबंधित वंशज सर्च के लिए दायरे में बने रहे।
सार्वजनिक-शेयर संदर्भ में, यह बहुत मायने रखता है क्योंकि सर्च शाखा सामान्य प्रमाणित उपयोगकर्ता अनुमति संदर्भ के बिना चलती है। इसलिए एक बार जब प्रतिबंधित वंशज खोजने योग्य पेज सेट में शामिल हो गए, तो उनका मेटाडेटा प्रतिक्रिया के माध्यम से लीक हो सकता था।
क्योंकि हमलावर को प्रमाणित खाते की आवश्यकता नहीं है।
उन्हें केवल चाहिए:
एक बार यह शर्त मौजूद होने पर, एक सार्वजनिक आगंतुक शेयर-सर्च एंडपॉइंट क्वेरी कर सकता है और प्राप्त कर सकता है:
यह गोपनीयता लीक पैदा करने के लिए पर्याप्त है, भले ही पूरा पेज बॉडी वापस न आए।
महत्वपूर्ण अंतर यह है कि एप्लिकेशन पहले से ही इच्छित सुरक्षा मॉडल को स्पष्ट रूप से संकेतित करता है।
सार्वजनिक ट्री एंडपॉइंट प्रतिबंधित वंशजों को छुपाता है।
तो असली प्रश्न यह नहीं है:
"क्या सर्च गलती से एक व्यापक परिणाम सेट लौटाती है?"
असली प्रश्न यह है:
"क्या सर्च एक प्राधिकरण निर्णय का उल्लंघन कर रही है जो पहले से ही उसी सार्वजनिक शेयर सीमा के लिए कहीं और लागू किया गया है?"
Docmost में, ऐसा ही था।
यह इसे इससे बदल देता है:
में:
यही कारण है कि यह एक वास्तविक भेद्यता है।
मैंने दो प्रासंगिक सार्वजनिक एंडपॉइंट की तुलना करके समस्या को मान्य किया।
पहले, मैंने सार्वजनिक शेयर कुंजी का उपयोग करके सामान्य सार्वजनिक ट्री एंडपॉइंट का परीक्षण किया।
उदाहरण अनुरोध:
POST /api/shares/tree HTTP/1.1
Host: 127.0.0.1:6752
Content-Type: application/json
{
"shareId": "public-share-key"
}
प्रतिक्रिया ने पेज ट्री में केवल सार्वजनिक चाइल्ड पेज लौटाया।
प्रतिनिधि परिणाम:
{
"pageTree": [
{
"id": "public-child",
"title": "Public roadmap"
}
]
}
इसने अपेक्षित उत्पाद व्यवहार स्थापित किया:
फिर मैंने एक ऐसी शब्द का उपयोग करके सार्वजनिक शेयर सर्च एंडपॉइंट को क्वेरी किया जो प्रतिबंधित वंशज के अंदर दिखाई देता था।
उदाहरण अनुरोध:
POST /api/search/share-search HTTP/1.1
Host: 127.0.0.1:6752
Content-Type: application/json
{
"shareId": "public-share-key",
"query": "salary"
}
प्रतिक्रिया में फिर भी प्रतिबंधित चाइल्ड शामिल था:
{
"items": [
{
"id": "public-child",
"title": "Public roadmap",
"highlight": "release plan and milestones"
},
{
"id": "restricted-child",
"title": "Payroll Q4",
"highlight": "salary bands and bonus targets"
}
]
}
इसने मुख्य दावा साबित कर दिया:
इस समस्या का सबसे मजबूत हिस्सा अकेला दूसरा अनुरोध नहीं है।
यह दोनों एंडपॉइंट के बीच का अंतर है।
यह दर्शाता है कि उत्पाद में पहले से ही सार्वजनिक शेयरों के लिए एक इच्छित प्रतिबंध मॉडल है।
प्रतिबंधित वंशज सार्वजनिक आगंतुक को दिखाई नहीं देना चाहिए।
यह साबित करता है कि सर्च पथ उसी सीमा को तोड़ता है।
यह समस्या को अपेक्षित सर्च व्यवहार या दस्तावेज़ीकरण अंतर के रूप में खारिज करना कठिन बनाता है।
एप्लिकेशन स्वयं ट्री प्रतिक्रिया के माध्यम से नियम स्थापित करता है, फिर सर्च प्रतिक्रिया के माध्यम से इसका उल्लंघन करता है।
यह शक्तिशाली सबूत है।
यह समस्या पूरे वर्कस्पेस में मनमानी सामग्री को उजागर नहीं करती है।
इसका दायरा इससे संकरा है।
लेकिन प्रभावित सार्वजनिक शेयर सबट्री के भीतर, यह अभी भी हमलावर को उपयोगी अनधिकृत जानकारी देता है:
छोटे स्निपेट भी मायने रख सकते हैं।
एक शीर्षक जैसे:
पहले से ही हमलावर के लिए सुरक्षा मूल्य पैदा करता है।
इसलिए, जबकि इसे अंततः मध्यम के रूप में वर्गीकृत किया गया था, यह अभी भी एक वैध गोपनीयता समस्या है जिसमें एक साफ और बचाव योग्य सीमा उल्लंघन है।
इस समस्या को असाइन किया गया था:
सलाहकार गंभीरता थी:
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:Nयह स्कोरिंग पूर्ण अनधिकृत दस्तावेज़ एक्सेस के बजाय एक संकीर्ण गोपनीयता लीक को दर्शाता है।
महत्वपूर्ण बिंदु यह है कि समस्या अभी भी मान्य है।
यहाँ दावा यह नहीं है:
दावा यह है:
यह एक वास्तविक प्राधिकरण-संबंधित सूचना प्रकटीकरण है।
कुछ लोग मेटाडेटा लीक को बहुत जल्दी खारिज कर देते हैं।
यह एक गलती है।
असली प्रश्न यह है कि क्या लीक किया गया डेटा एक इच्छित सीमा को पार करता है।
यहाँ, ऐसा हुआ।
यदि एप्लिकेशन कहता है:
लेकिन एक सार्वजनिक एंडपॉइंट फिर भी प्रकट करता है:
तो गोपनीयता मॉडल विफल हो गया है, भले ही प्रभाव सीमित हो।
यह इसे रिपोर्ट करने लायक बनाता है।
इस तरह के साफ, दायरे वाले और पुनरुत्पादनीय बग ठीक उसी तरह की समस्याएं हैं जो मजबूत सुरक्षा समीक्षा निर्णय को प्रदर्शित करने में मदद करती हैं।
सबसे सुरक्षित फिक्स दिशा यह है कि सार्वजनिक सर्च को सार्वजनिक ट्री फ़्लो के समान प्रतिबंध-जागरूक वंशज तर्क का उपयोग करना चाहिए।
व्यवहार में, इसका मतलब है कि शेयर-सर्च शाखा को इसके साथ वंशजों की गणना नहीं करनी चाहिए:
getPageAndDescendants(...)
इसे इसके बजाय सुरक्षित सार्वजनिक-शेयर ट्रैवर्सल के साथ संरेखित होना चाहिए और इसका उपयोग करना चाहिए:
getPageAndDescendantsExcludingRestricted(...)
एक वैकल्पिक फिक्स व्यापक गणना रखना और फिर सर्च क्वेरी के परिणाम लौटाने से पहले प्रतिबंधित वंशजों को स्पष्ट रूप से फ़िल्टर करना होगा।
लेकिन क्लीनर डिज़ाइन सरल है:
सर्च सीमा ब्राउज़ सीमा से मेल खानी चाहिए
यही वह सुरक्षा संपत्ति है जो विफल हुई।
यह समस्या GitHub के सुरक्षा रिपोर्टिंग प्रवाह के माध्यम से निजी रूप से रिपोर्ट की गई थी।
रिपोर्ट में दिखाया गया:
/api/shares/tree के माध्यम से इच्छित सुरक्षित व्यवहार/api/search/share-search के माध्यम से असंगत कमजोर व्यवहारसमस्या स्वीकार की गई और असाइन की गई:
CVE-2026-33146
अंतिम सलाहकार गंभीरता मध्यम थी, जो व्यापक गंभीरता के दावे की तुलना में संकीर्ण लीक दायरे में बेहतर फिट बैठती है।
यह निष्कर्ष की वैधता को कमजोर नहीं करता है।
यह बस इसके प्रभाव को अधिक सटीक रूप से परिभाषित करता है।
यहाँ मुख्य सबक सरल है:
एक सार्वजनिक एंडपॉइंट में कुछ छिपाना पर्याप्त नहीं है यदि कोई अन्य सार्वजनिक एंडपॉइंट इसे अभी भी प्रकट करता है।
बहुत सारे डेवलपर प्राधिकरण के बारे में केवल स्पष्ट रेंडरिंग पथ में सोचते हैं:
लेकिन वास्तविक सीमा व्यापक है।
आपको यह भी पूछना होगा:
Docmost में, उत्तर नहीं था।
यही असली सीख है।
यह भेद्यता आकर्षक पेलोड या जटिल शोषण श्रृंखलाओं के बारे में नहीं थी।
यह एक बहुत ही व्यावहारिक विश्वास-सीमा प्रश्न पूछने के बारे में थी।
Docmost ने प्रतिबंधित पेज को एक जगह छिपाया। फिर दूसरी जगह लीक कर दिया।
यही कारण है कि यह CVE-2026-33146 बन गया।