VSCode बग के ज़रिए 1-क्लिक में GitHub टोकन चोरी
(blog.ammaraskar.com)- github.dev
github.comसे मिले OAuth टोकन का इस्तेमाल करके ब्राउज़र VSCode में फ़ाइलें देखना, PR और commit करना संभव बनाता है, और यह टोकन किसी खास repository तक सीमित नहीं होता, इसलिए उपयोगकर्ता जिन सभी repositories तक पहुँच सकता है उन्हें पढ़ा और लिखा जा सकता है - VSCode webview
vscode-webview://...iframe के ज़रिए isolate किया जाता है, लेकिन keyboard shortcut UX के लिए webview काkeydowndid-keydownसंदेश के रूप में main window तक भेजा जाता है, जिससे अविश्वसनीय script उपयोगकर्ता के key input जैसे event भेज सकती है - मनचाहा text input HTML
<input>की वजह से काम नहीं करता, लेकिन default shortcutCtrl+Shift+A, recommended extension install notification, local workspace extensions और custom keybinding को मिलाकर extension install command चलाई जा सकती है - PoC में Jupyter notebook के Markdown cell से JavaScript चलाकर recommended extension install को accept किया जाता है, फिर नई keybinding से चुना हुआ extension install किया जाता है, और उसके बाद GitHub API token तथा private repository की सूची दिखाई जाती है
- desktop VSCode भी इसी कमजोरी से प्रभावित है, लेकिन वहाँ attacker को repository clone करवाकर notebook खुलवाना होगा; github.dev उपयोगकर्ताओं के लिए site data साफ़ करना एक बचाव है ताकि शुरुआती confirmation dialog फिर से दिखाई दे
भेद्यता का अवलोकन
- github.dev किसी सुलभ GitHub repository URL में
github.comकोgithub.devसे बदलने या menu item पर क्लिक करने पर ब्राउज़र में चलने वाला हल्का VSCode खोल देता है - यह browser VSCode repository फ़ाइलें देख सकता है, private repositories भी खोल सकता है, और PR भेजने व commit बनाने की सुविधा भी देता है
- github.com उपयोगकर्ता की ओर से GitHub के साथ इंटरैक्ट करने वाला OAuth token
github.devको POST करता है, और यह token उस खास repository तक सीमित नहीं होता जिससे उपयोगकर्ता इंटरैक्ट कर रहा था - attacker सिर्फ लिंक क्लिक करवाकर पढ़ने-लिखने की अनुमति वाला GitHub token चुरा सकता है, और इसमें private repositories भी शामिल हो सकती हैं
Webview isolation और key input forwarding की समस्या
- VSCode webviews JavaScript execution को isolate करने के लिए main VSCode window से अलग origin वाले
<iframe>का उपयोग करते हैं - Jupyter notebook output
vscode-webview://...origin वाले<iframe>में render होता है, जबकि main Electron windowvscode-file://...origin का उपयोग करती है - इस isolation की वजह से notebook में HTML rendering या JavaScript-आधारित interactive widget होने पर भी iframe के अंदर से Electron की Node.js API या VSCode API को call नहीं किया जा सकता
- Markdown preview जैसी सुविधाएँ, जहाँ main window और webview को साथ काम करना होता है, Window.postMessage() API से संदेशों का आदान-प्रदान करती हैं
- VSCode webview के अंदर focus होने पर भी
Ctrl+Shift+Pजैसे shortcuts काम करते रहें, इसके लिएdid-keydownevent main window तक forward किया जाता है - webview के अंदर की अविश्वसनीय script सीधे
keydownevent पैदा करके ऐसा दिखा सकती है जैसे उपयोगकर्ता ने खुद key दबाई हो
attack chain
Ctrl+Shift+Pसे command palette खोली जा सकती है, लेकिन क्योंकि command palette HTML<input>का उपयोग करती है, इसलिए मनचाहा string type कराने वाला तरीका काम नहीं करता- arrow keys और
Enterजैसे input, जोkeydownसे handle होते हैं, इस्तेमाल किए जा सकते हैं, और VSCode के default shortcut set का भी लाभ उठाया जा सकता है Ctrl+Shift+A“Notifications: Accept Notification Primary Action” की default keybinding है, और यह आख़िरी VSCode notification के primary button को दबाती है.vscode/extensions.jsonमें recommended extensions डालने पर VSCode install notification दिखाता है, लेकिन VSCode 1.97 का publisher trust system नए publisher की extension install करते समय अलग trust dialog दिखाता हैTabसे button focus बदला जा सकता है, लेकिन “Trust Publisher & Install” button काEnterhandling उसी button के अपनेkeydownसे बंधा है, इसलिए केवल इस रास्ते से install पूरा करना मुश्किल है- local workspace extensions trusted workspace में
.vscode/extensionsके भीतर मौजूद extension को सीधे install करने देती हैं, और github.dev/web workspace हमेशा trusted स्थिति में होता है - local workspace extension को सीधे चलाने की कोशिश करने पर extension worker
vscode-cdn.netसे आई extension की अपेक्षा करता है, इसलिए CSP error आता है - इसके बजाय local workspace extension की
package.jsonमें custom keybinding जोड़ी जा सकती है, और वह keybindingworkbench.extensions.installExtensionकोskipPublisherTrustcontext के साथ call करा सकती है
PoC का काम करने का तरीका और प्रभाव
- ज़रूरी setup एक ऐसी repository है जिसमें Jupyter notebook और local workspace extension मौजूद हों
- notebook का Markdown cell image के
onerrorattribute के ज़रिए JavaScript चला सकता है - payload तब तक इंतज़ार करता है जब तक VSCode recommended extension install notification न दिखा दे, फिर notification की primary action accept करने के लिए
Ctrl+Shift+Aevent भेजता है - इसके बाद extension के install और activate होने, तथा custom keybinding उपलब्ध होने तक इंतज़ार किया जाता है, फिर चुनी हुई extension install कराने के लिए
Ctrl+F1event trigger किया जाता है - PoC से install की गई extension GitHub API token हासिल करती है और
https://api.github.com/user/reposको query करके सुलभ private repositories निकालती है, फिर token और repository सूची को info box में दिखाती है - PoC चलने के बाद github.dev data साफ़ करना या PoC extension हटाना ज़रूरी है; नहीं हटाने पर यह सभी github.dev pages पर बना रहता है
- desktop VSCode में भी यही कमजोरी है, लेकिन attacker को पीड़ित से repository clone करवानी होगी और webview script payload वाला notebook खुलवाना होगा
- यदि पीड़ित जिस webview को खोलता है उसमें कोई और XSS भी हो, तो desktop पर यह व्यवहारिक रूप से full remote code execution तक पहुँच सकता है
बचाव और mitigation factors
- अगर आपने पहले कभी github.dev इस्तेमाल नहीं किया है, तो वेबसाइट में प्रवेश पर एक dialog आता है जिस पर क्लिक करना पड़ता है, जिससे attack page से निकलने का मौका मिल जाता है
- github.dev की cookies और local site data साफ़ करने पर यह शुरुआती dialog फिर से दिखाई दे सकता है
- Chrome में URL bar के icon पर क्लिक करके Cookies and site data > Manage on-device site data में जाकर संबंधित domain data हटाया जा सकता है
- अगर उपयोगकर्ता पहले ही github.dev dialog पार कर चुका है और browser local storage साफ़ नहीं किया है, तो github.dev में CSRF token जैसी सुरक्षा नहीं है, इसलिए इंटरनेट का कोई भी link attack की ओर redirect कर सकता है
- VSCode सिर्फ iframe isolation पर निर्भर नहीं करता, बल्कि सख्त Content Security Policy और DOMPurify का भी उपयोग करता है
- extension page के Markdown preview में
script-src 'none'इस्तेमाल करके मनमाना JavaScript execution रोका जाता है, इसलिए केवल extension link से desktop 1-क्लिक RCE जैसा बड़ा प्रभाव रुक जाता है
सार्वजनिक खुलासे की पृष्ठभूमि और समयरेखा
- MSRC ने पहले VSCode bug reports को चुपचाप fix किया था, credit नहीं दिया था, और उन्हें बिना security impact के चिह्नित किया था
- हाल की Starlabs की VSCode XSS bug report को भी ineligible और low severity बताया गया था
- संभव है VSCode team को UI/UX और security के बीच संतुलन बनाने के लिए अधिक समय चाहिए था, लेकिन security researchers के समय और मेहनत को हल्के में नहीं लेना चाहिए—इसी वजह से full disclosure चुना गया
- 2 जून 2026 को पोस्ट प्रकाशित होने से एक घंटा पहले GitHub security पक्ष के मौजूदा संपर्क को प्रस्तावित disclosure की सूचना दी गई
- उसी दिन भेद्यता सार्वजनिक हुई और VSCode issue tracker में भी दर्ज की गई
1 टिप्पणियां
Hacker News की राय
यह अच्छा सार-संक्षेप था, और बड़े परिप्रेक्ष्य में देखें तो वेब में एम्बेडेड VSCode editor का GitHub में लॉग-इन होना ही खटकता है
defense-in-depth है या नहीं, उससे अलग, मूल समस्या वही है और उसी वजह से attack surface बहुत बढ़ जाता है। यह वैसा ही है जैसे किसी workstation पर एक plain-text GitHub API token छोड़ दिया जाए, जिसके पास सभी अधिकार हों और जिसे कोई malicious NPM package खोज सके
आदर्श रूप से browser IDE को अस्थायी, repository-विशिष्ट permission scope या ऐसे token के साथ चलना चाहिए जो सिर्फ उस repository पर pull/push कर सके, और github.com web session बिल्कुल न हो। अगर पूरा GitHub web UI चाहिए तो github.com पर वापस जाएँ, और github.dev को single-repository service की तरह रखा जाए
लेकिन यह users के लिए असुविधाजनक होगा, implement करना भी कठिन है, और संभव है कि github.dev टूलिंग में यह धारणा ऐतिहासिक रूप से गहराई से बसी हो
github.dev के लिए भी इस तरीके पर गंभीरता से विचार होना चाहिए
[1] https://orca.security/resources/blog/hacking-github-codespac...
इससे भी बुरी बात यह है कि developers खुद भी इस पर बहुत ध्यान देते नहीं दिखते
keydownhandler तक propagate नहीं होने देना चाहिएdesktop पर इसे बदलकर Electron को सीधे intercept करने देना बेहतर होगा और यह feature हटा देना चाहिए, और web पर इसे default रूप से disabled होना चाहिए
दूसरे Git hosting में भी ऐसा कुछ है या नहीं, यह पता नहीं
सच कहूँ तो LLM agents के साथ भी ऐसा ही होना चाहिए। LLM को सीधे push करने देना लापरवाही लगता है
यह attack खास तौर पर मुश्किल इसलिए है क्योंकि VSCode extensions editor के ही बराबर trust level पर चलती हैं, और ज़्यादातर developers बिना permissions की समीक्षा किए दर्जनों extensions install कर लेते हैं
अगर कोई malicious या hijacked extension चुपचाप GitHub token exfiltrate कर दे, तो network monitoring के बिना पता लगाना मुश्किल है, और यही isolated profile में extensions चलाने के पक्ष में तर्क है
सबसे अच्छा तरीका है GitHub से हटकर self-hosted internal GitLab/Forgejo पर जाना और GitHub को पूरी तरह block कर देना
हाल ही में मेरे साथ भी कुछ ऐसा ही हुआ। GitHub token और Cloudflare token चोरी हो गए
मेरा मानना है कि सुरक्षा को गंभीरता से लेने पर भी, अगर समय काफी लंबा हो तो आखिरकार चोट लग ही जाती है। सबसे अच्छा तरीका है चीज़ों को अलग रखना और blast radius को नियंत्रित करना
किसी पर, किसी चीज़ पर भरोसा मत करो, OrbStack इस्तेमाल करो, और हमेशा इस मानकर काम करो कि token कभी न कभी leak होंगे
मेरा workflow पूरी तरह टूट गया था, लेकिन शुक्र है कि tokens लेने वाला पक्ष spam bot के ज़्यादा करीब था। उसने ढेर सारे fake spam pages बनाए और cryptocurrency mining की कोशिश की
सबसे गहरा असर यह रहा कि खुद के उल्लंघन का एहसास बना रहा। सब लोग सावधान रहें
MSRC को VSCode bug report करने पर उन्होंने चुपचाप fix कर दिया — यह हिस्सा बिल्कुल typical MSRC जैसा लगा। लगता है उन्हें समझ आ गया है कि researchers वैसे भी मुफ्त में report करते रहेंगे, इसलिए बदलने की कोई खास वजह उन्हें नहीं दिखती
इस मामले की specifics मुझे नहीं पता, लेकिन पहले मैंने Bountysource और HackerOne के जरिए bug bounty programs चलाए हैं। कभी-कभी ऐसा होता है कि security team के पूरी तरह evaluate करने से पहले report development team तक पहुँच जाती है
उस समय developer चुपचाप fix कर सकता है। कभी यह इस चिंता से होता है — चाहे वह तर्कसंगत हो या नहीं — कि security bug से जुड़ना उसके लिए बुरा दिखेगा या promotion के अवसरों को प्रभावित करेगा। नतीजतन जब security team reproduce करने की कोशिश करती है, तब तक vulnerability गायब हो चुकी होती है
MSRC के नज़रिए से बस इतना दिखता है कि दिए गए reproduction steps अब काम नहीं कर रहे। उन्हें internal bug history या यह नहीं दिखता कि किसी ने पहले ही patch कर दिया है। इसलिए भले ही मूल finding वैध रही हो, report को invalid कहकर बंद कर दिया जाता है
इस exploit पर लगाया गया समय लगभग दान की तरह था, ताकि VS Code की security response सुधारने की ज़रूरत पर ध्यान जाए, इसलिए इसके लिए आभारी हूँ। चाहें तो वे बीच में छोड़ भी सकते थे, लेकिन फिर भी मदद कर रहे हैं
समझ नहीं आता कि और ज़्यादा डेवलपर Neovim को क्यों नहीं आज़माते।
यह शायद पसंद की बात हो सकती है, लेकिन मुझे ऐसा छोटा setup पसंद है जिसमें यह समझा जा सके कि क्या installed है और क्या चल रहा है। जब VSCode, browser IDE, extensions, sync, tokens और random plugins सब मिल जाते हैं, तो यह समझना मुश्किल हो जाता है कि किसे किस चीज़ की access है
यह Microsoft के official Python extension की feature थी, और बाकी मामलों में वही शायद एकमात्र extension था जो कुछ हद तक usable था, लेकिन इसने मेरे project में इस्तेमाल हो रही library version से अलग version की type definitions install कर दी थीं। यह बिना verify किए गए third-party code को बड़ी सहजता से run करने जैसा लगा, जिससे मैं बहुत असहज हो गया, और इसे setting से बंद करना भी संभव नहीं लग रहा था
मैं कहना चाहूँगा कि “उसके बाद कभी पीछे मुड़कर नहीं देखा”, लेकिन सच यह है कि पिछले 1~2 साल में Neovim ने लगभग हर upgrade पर मेरी config को नियमित रूप से तोड़ना शुरू कर दिया है। कभी न कभी ऐसा हो सकता है, इसका आभास पहले से था। सख्ती से कहें तो 10 साल बीत जाने के बाद भी nvim ने अभी तक पहला stable version जारी नहीं किया है, इसलिए इसकी instability के लिए उसे दोष नहीं दिया जा सकता, लेकिन यह याद रखने लायक बात है
मैं फिर से plain Vim पर लौटने के बारे में सोच रहा हूँ। इससे काफी convenience features खो दूँगा, लेकिन कम-से-कम काम करते समय टूटी हुई functionality को debug करने की नौबत कम आए तो अच्छा होगा
इसके लिए ढेर सारे plugins install करने या SpaceVim जैसी किसी चीज़ का इस्तेमाल करने की ज़रूरत नहीं पड़ती। एक बार देखकर शायद आपको भी पसंद आए
nvim की आदत पड़ने में समय लगता है, लेकिन एक बार आदत हो जाए तो यह तेज़ है। फिर भी, लोग अपनी comfort zone में क्यों रहते हैं, यह समझ में आता है
public disclosure करना अच्छी बात थी। MSRC से नाराज़ लोगों की संख्या बहुत ज़्यादा है, और Nightmare Eclipse जैसी स्थिति में अब यह उफान पर पहुँचती दिख रही है
शायद ऐसी disclosures जमा होती रहें तो MSRC आत्ममंथन करे और समझे कि समस्या वही है। इसकी संभावना कम लगती है, लेकिन उम्मीद तो की जा सकती है
फिर भी, कम-से-कम कोशिश तो करनी चाहिए थी, या public करने से कई दिन पहले बता देना चाहिए था। क्या होता, यह पहले से कौन जानता है
लेख बहुत अच्छा था, लेकिन आख़िरी हिस्से में मैं थोड़ा भ्रमित हो गया। मैं बस यह पक्का करना चाहता हूँ कि मैंने सही समझा है या नहीं
लेखक ने कहा कि नए publisher trust system की वजह से सिर्फ shortcut trick से malicious extension को सीधे install नहीं किया जा सकता, और publisher check के बिना local workspace extension के ज़रिए इसे bypass किया जा सकता है, लेकिन CSP उसे रोक देता है
इसका समाधान शायद एक local workspace extension install करना है जो “publisher verification के बिना extension install” वाले shortcut को bind कर दे
तो मैं सोच रहा हूँ कि 1) क्या इसका मतलब है कि दो extensions चाहिए? पहला सिर्फ key binding करने वाला local extension, और दूसरा असली malicious extension, जिसे CSP की वजह से local होने की ज़रूरत भी नहीं है और शायद local हो भी नहीं सकता; और 2) क्या CSP सिर्फ local extension के JS को block करता है, लेकिन
package.jsonया shortcut जोड़ने की capability को नहीं रोकता?सबसे सीधा execution पाने के लिए आप
my-extension/extension.jsडालने की कोशिश कर सकते हैं, लेकिन CSP उसे block कर देता है। हालांकिscript-srcCSP सिर्फ scripts को block करता है, इसलिएpackage.jsonलाने की अनुमति रहती है। उसी का इस्तेमाल करके key binding contribute की जाती हैMSRC स्थिति सच में अविश्वसनीय है
शायद इससे बेहतर resources भी हों, लेकिन मुझे लगता है कि The Primeagen का यह वीडियो शुरुआत के लिए अच्छा material है
https://www.youtube.com/watch?v=9kxx5xp5nTQ
“इस व्यवहार की अनुमति देने का एकमात्र तरीका यह है कि अलग-अलग origin वाले दो web pages
Window.postMessage()API के ज़रिए सहयोग करें” — इस हिस्से पर एक छोटी-सी nitpick हैiframe या parent window
location.anchorproperty बदलने के तरीके से भी communicate कर सकते हैं