
CVE-2026-18963 के लिए प्रूफ़ ऑफ़ कॉन्सेप्ट और भेद्यता जाँचकर्ता, जो Keycloak reset-credentials प्रवाह में एक अनधिप्रमाणित खाता अधिग्रहण है। एकल-फ़ाइल Python, वैकल्पिक Playwright ब्राउज़र घटक।
Keycloak reset-credentials फ़्लो बायपास के लिए एक प्रूफ़ ऑफ़ कॉन्सेप्ट और भेद्यता जाँचकर्ता, जिसमें एक वैकल्पिक ब्राउज़र घटक है जो परिणामी स्थिति को एक वास्तविक Chrome विंडो में प्रस्तुत करता है।
यह टूल एक एकल फ़ाइल, cve_2026_18963_poc.py है, जो Python मानक लाइब्रेरी के विरुद्ध लिखी गई है। Playwright एकमात्र तृतीय-पक्ष निर्भरता है और इसे आलसी रूप से आयात किया जाता है, इसलिए HTTP पक्ष बिना कुछ स्थापित किए एक स्टॉक इंटरप्रेटर पर चलता है।
cve_2026_18963_poc.py 1009 lines, Python 3.10 or newer
श्रेय। CVE-2026-18963 की रिपोर्ट Red Hat को James Paremain ने की थी, जिन्हें विक्रेता की सलाह में श्रेय दिया गया है। Orevim ने इस भेद्यता की खोज या रिपोर्ट नहीं की। यह रिपॉज़िटरी प्रकाशित सलाह से लिखा गया एक स्वतंत्र प्रूफ़ ऑफ़ कॉन्सेप्ट है।
CVE-2026-18963, Keycloak के forgot-password फ़्लो में एक प्रमाणीकरण बायपास है। यह दो दोष हैं जो मिलकर काम करते हैं।
अनस्कोप्ड नोट। जब कोई उपयोगकर्ता authenticator selection स्क्रीन खोलता है,
तो Keycloak authentication session में एक AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED नोट लिखता है।
यह नोट एक सादा बूलियन है। यह दर्ज करता है कि एक selection स्क्रीन प्रदर्शित हुई थी, यह नहीं कि किस execution ने उसे प्रदर्शित किया। यह नोट उस execution से अधिक जीवित रहता है जिसने इसे सेट किया था।
असुरक्षित हैंडलर। ResetCredentialEmail.action() resolved उपयोगकर्ता पर emailVerified सेट करता है और उस action token की जाँच किए बिना success() कॉल करता है जो ईमेल किए गए लिंक को कथित रूप से साथ ले जाना चाहिए। यह मेथड मान लेता है कि इस तक केवल उस लिंक का अनुसरण करके ही पहुँचा जा सकता है।
श्रृंखलाबद्ध रूप से, एक अनप्रमाणित कॉलर username execution के विरुद्ध नोट सेट करता है, फ़्लो को आगे बढ़ाता है ताकि email execution वर्तमान बन जाए, और फिर reset URL में पुनः प्रवेश करता है। पुराना नोट selection स्क्रीन को email execution से बंधा हुआ रेंडर करने का कारण बनता है। उस execution के loginAction पर एक खाली बॉडी पोस्ट करने से असुरक्षित हैंडलर सीधे आह्वान हो जाता है। फ़्लो UPDATE_PASSWORD required action तक आगे बढ़ जाता है, बिना कोई ईमेल पढ़े।
| पहचानकर्ता | CVE-2026-18963, GHSA-4gv3-mc9p-5wqc |
| वर्ग | CWE-640, भूल गए पासवर्ड के लिए कमज़ोर पासवर्ड रिकवरी तंत्र |
| CVSS v3.1 | 9.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N |
| प्रभावित | >= 26.0.0, < 26.4.15, >= 26.5.0, < 26.6.6, >= 26.7.0, < 26.7.2 |
| पैच किया गया | 26.4.15, 26.6.6, 26.7.2 में। 26.8.0 लाइन फ़िक्स के साथ आती है |
| पैकेज | org.keycloak:keycloak-services (Maven) |
| प्रकाशित | 18 अगस्त, 2026 |
| रिपोर्ट किया गया | James Paremain द्वारा, Red Hat की सलाह में श्रेय दिया गया |
एकमात्र पूर्वशर्त यह है कि realm अनप्रमाणित उपयोगकर्ताओं को पासवर्ड रिकवरी प्रदान करता हो। किसी क्रेडेंशियल, टोकन, या पूर्व सत्र की आवश्यकता नहीं है।
आठ अनुरोध, क्रम में। टैग उन स्टेप लेबल से मेल खाते हैं जो टूल प्रिंट करता है और उन फ़ाइलनामों से जिन्हें यह --out के अंतर्गत लिखता है।
| # | टैग | मेथड | यह क्या करता है |
|---|---|---|---|
| 1 | login | GET | Authorization URL। authentication session स्थापित करता है और reset लिंक देता है। |
| 2 | reset | GET | Reset-credentials पेज। username फ़ॉर्म ले जाता है। |
| 3 | tryanother | POST | tryAnotherWay=on। अनस्कोप्ड नोट लिखता है। |
| 4 | username | POST | पहचानकर्ता। फ़्लो को आगे बढ़ाता है ताकि email execution वर्तमान बन जाए। यदि पहचानकर्ता resolve होता है तो recovery मेल भेजता है। |
| 5 | reenter | GET | फिर से reset URL। पुराना नोट selector को email execution से बंधा हुआ रेंडर करता है। |
| 6 | action | POST | उस execution के loginAction पर खाली बॉडी। असुरक्षित हैंडलर का आह्वान करता है। |
| 7 | required-action | GET | UPDATE_PASSWORD पेज तक Location का अनुसरण करता है। |
| 8 | setpassword | POST | नया पासवर्ड। केवल --set-password के साथ भेजा जाता है। |
स्टेप 6 ही शोषण है, और खाली बॉडी निर्णायक है। इसके बजाय authenticationExecution=<id> पोस्ट करना सामान्य selector इंटरैक्शन है: यह execution बदलता है और recovery मेल पुनः भेजता है, जो कभी दोष तक नहीं पहुँचता। खाली POST किसी चुनौती का उत्तर नहीं देता, इसलिए Keycloak उस execution के लिए हैंडलर कॉल करता है जिसे पुराने नोट ने वर्तमान छोड़ा था।
# Decide whether the instance is affected. Changes nothing, sends no mail.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
--client-id account-console --check
# Additionally report which identifiers resolve to a real account.
# Resolving accounts receive a recovery email. See the note below.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
--client-id account-console --check --users-file names.txt --rate 0.25
# Reach the set-password form for one account and stop there.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
--client-id account-console --username [email protected]
# Complete the takeover. This locks the account holder out.
./cve_2026_18963_poc.py --url https://sso.example.com --realm demo \
--client-id account-console --username [email protected] \
--set-password 'N3w-passw0rd!'
--check <16 hex>@<8 hex>.invalid के रूप के एक यादृच्छिक पहचानकर्ता के साथ जाँच करता है। .invalid TLD RFC 2606 द्वारा आरक्षित है और हल नहीं हो सकता, इसलिए जाँच किसी वास्तविक खाते से टकरा नहीं सकती और मेल भेजने का कारण नहीं बन सकती। यह किसी को छुए बिना बिल्ड की स्थिति स्थापित करती है।
--usersजोड़ने से यह बदल जाता है। चरण 4 सामान्य forgot-password सबमिशन है। SMTP कॉन्फ़िगर किए गए realm पर, ऐसा पहचानकर्ता जो ईमेल पते वाले उपयोगकर्ता को हल करता है, प्रभावित और पैच किए गए बिल्ड दोनों पर ही एक वास्तविक पासवर्ड-रिकवरी ईमेल प्राप्त करता है। बेयर जाँच ऐसा नहीं करती, क्योंकिResetCredentialEmail.authenticate()तब कुछ नहीं भेजता जब उपयोगकर्ता null हो।--check --usersको ऐसे प्रवाह के रूप में मानें जो वास्तविक लोगों को सूचित करता है और इसे चलाने से पहले पुष्टि करें कि यह आपके प्राधिकरण के भीतर है।
टूल चरण 6 की प्रतिक्रिया पर वर्गीकृत करता है, अर्थात् खाली POST।
| प्रतिक्रिया | परिणाम | अर्थ |
|---|---|---|
| 400 | account-absent | हैंडलर बिना किसी action token के चला और किसी उपयोगकर्ता को हल नहीं किया। बिल्ड प्रभावित है। |
302 with Location | form-reached | हैंडलर चला और खाता हल हो गया। प्रभावित, और यह पहचानकर्ता वास्तविक है। |
| Anything else | not-vulnerable | खाली POST आगे नहीं बढ़ा। |
| चरण 5 पर कोई selector नहीं | not-vulnerable | पुराने नोट का सम्मान नहीं किया गया। |
| चरण 8 के बाद 302 | password-set | पासवर्ड बदल गया और realm ने एक सत्र जारी किया। |
| पुनःप्रयास बजट से आगे 429 | rate-limited | कोई निर्णय नहीं। रन रुक गया। |
| किसी भी थ्रॉटलिंग के बाद पहुँचा गया नकारात्मक | inconclusive | नीचे देखें। |
400 महत्वपूर्ण है। यह बिल्ड प्रभावित है को यह खाता मौजूद है से अलग करता है, जिससे --check किसी एक भी वास्तविक उपयोगकर्ता को सूचीबद्ध किए बिना किसी इंस्टेंस के विरुद्ध जोखिम स्थापित कर सकता है। पहचानकर्ताओं को हल करना फिर एक अलग, ऑप्ट-इन प्रश्न है।
एक नकारात्मक तभी विश्वसनीय है जब कुछ भी थ्रॉटल न किया गया हो। Keycloak प्रमाणीकरण सत्र को अपनी घड़ी पर समाप्त करता है। श्रृंखला के बीच में 429 एक बैकऑफ़ का खर्च है, और लंबी नींद के बाद फिर से शुरू होने वाली श्रृंखला ठीक वही पृष्ठ लौटाती है जो एक पैच किया गया बिल्ड लौटाता है। उसे प्रभावित नहीं के रूप में रिपोर्ट करना वह एक विफलता मोड है जो एक चेकर में नहीं होना चाहिए, इसलिए थ्रॉटल घटना के बाद पहुँचे गए किसी भी नकारात्मक को थ्रॉटल गणना और धीमे पुनः चलाने की सलाह के साथ inconclusive में डाउनग्रेड किया जाता है।
परिनियोजन के बारे में कुछ भी हार्डकोडेड नहीं है। टूल वह पढ़ता है जिसकी उसे आवश्यकता होती है: