1 poin oleh GN⁺ 3 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • github.dev menggunakan token OAuth yang diterima dari github.com untuk membuka file, membuat PR, dan melakukan commit di VSCode browser, dan karena token ini tidak dibatasi ke repositori tertentu, token tersebut dapat membaca dan menulis ke seluruh repositori yang bisa diakses pengguna
  • Webview VSCode diisolasi dengan iframe vscode-webview://..., tetapi demi UX shortcut keyboard, keydown dari webview diteruskan ke jendela utama sebagai pesan did-keydown, sehingga skrip tidak tepercaya dapat mengirim event seolah-olah itu input keyboard pengguna
  • Input teks arbitrer tidak berhasil karena HTML <input>, tetapi dengan menggabungkan shortcut bawaan Ctrl+Shift+A, notifikasi instalasi extension yang direkomendasikan, local workspace extensions, dan keybinding kustom, perintah instalasi extension dapat dijalankan
  • PoC menjalankan JavaScript dari sel Markdown Jupyter notebook, menerima instalasi extension yang direkomendasikan, lalu memasang extension yang dipilih lewat keybinding baru, kemudian menampilkan token GitHub API dan daftar repositori privat
  • VSCode desktop juga memiliki kerentanan yang sama, tetapi penyerang harus membujuk korban untuk meng-clone repositori dan membuka notebook, dan pengguna github.dev perlu menghapus data situs agar dialog konfirmasi awal muncul kembali sebagai langkah pertahanan

Ringkasan kerentanan

  • github.dev membuka VSCode ringan yang berjalan di browser ketika URL repositori GitHub yang dapat diakses diubah dari github.com menjadi github.dev atau saat item menu diklik
  • VSCode browser ini dapat melihat file repositori, juga dapat membuka repositori privat, serta bisa mengirim PR dan membuat commit
  • github.com mengirim token OAuth ke github.dev melalui POST agar dapat berinteraksi dengan GitHub atas nama pengguna, dan token ini tidak dibatasi pada repositori tertentu yang sedang diakses pengguna
  • Penyerang dapat mencuri token GitHub dengan hak baca-tulis hanya dengan klik tautan, termasuk akses ke repositori privat milik target

Isolasi webview dan masalah penerusan input keyboard

  • VSCode webviews menggunakan <iframe> dengan origin berbeda dari jendela utama VSCode untuk mengisolasi eksekusi JavaScript
  • Output Jupyter notebook dirender di dalam <iframe> dengan origin vscode-webview://..., sedangkan jendela utama Electron menggunakan origin vscode-file://...
  • Berkat isolasi ini, notebook yang memakai tampilan HTML atau widget interaktif berbasis JavaScript tidak dapat memanggil API Node.js Electron atau API VSCode dari dalam iframe
  • Fitur yang mengharuskan jendela utama dan webview bekerja sama, seperti pratinjau Markdown, saling bertukar pesan melalui API Window.postMessage()
  • VSCode meneruskan event did-keydown ke jendela utama agar shortcut seperti Ctrl+Shift+P tetap berfungsi meskipun fokus berada di dalam webview
  • Skrip tidak tepercaya di dalam webview dapat memicu event keydown secara langsung untuk menyamar seolah pengguna menekan tombol

Rantai serangan

  • Ctrl+Shift+P memang bisa membuka command palette, tetapi karena command palette memakai HTML <input>, pendekatan memasukkan string arbitrer tidak berhasil
  • Input seperti tombol arah dan Enter yang diproses lewat keydown tetap bisa digunakan, demikian juga kumpulan shortcut bawaan VSCode
  • Ctrl+Shift+A adalah keybinding default untuk “Notifications: Accept Notification Primary Action” dan menekan tombol utama pada notifikasi VSCode terakhir
  • Jika extension yang direkomendasikan dimasukkan ke .vscode/extensions.json, VSCode akan menampilkan notifikasi instalasi, tetapi sistem publisher trust di VSCode 1.97 akan memunculkan dialog kepercayaan terpisah saat memasang extension dari publisher baru
  • Navigasi tombol dengan Tab memang dimungkinkan, tetapi pemrosesan Enter pada tombol “Trust Publisher & Install” terikat ke keydown tombol itu sendiri, sehingga jalur ini saja sulit dipakai untuk menyelesaikan instalasi
  • Local workspace extensions memungkinkan extension di .vscode/extensions dipasang langsung di workspace tepercaya, dan github.dev/web workspace selalu berada dalam status tepercaya
  • Jika local workspace extension dicoba dijalankan langsung, extension worker akan mengharapkan extension berasal dari vscode-cdn.net, sehingga muncul error CSP
  • Sebagai gantinya, keybinding kustom dapat ditambahkan ke package.json milik local workspace extension, lalu keybinding itu dibuat memanggil workbench.extensions.installExtension dengan konteks skipPublisherTrust

Cara kerja PoC dan dampaknya

  • Konfigurasi yang dibutuhkan adalah repositori yang berisi Jupyter notebook dan local workspace extension
  • Sel Markdown notebook dapat menjalankan JavaScript melalui atribut onerror pada gambar
  • Payload menunggu sampai VSCode menampilkan notifikasi instalasi extension yang direkomendasikan, lalu mengirim event Ctrl+Shift+A untuk menerima aksi utama notifikasi tersebut
  • Setelah itu, payload menunggu sampai extension terpasang dan aktif serta keybinding kustom tersedia, lalu memicu Ctrl+F1 untuk menjalankan instalasi extension yang dipilih
  • Extension yang dipasang dalam PoC mengambil token GitHub API, meminta https://api.github.com/user/repos untuk mendapatkan repositori privat yang dapat diakses, lalu menampilkan token dan daftar repositori di kotak informasi
  • Setelah PoC dijalankan, data github.dev harus dihapus atau extension PoC harus dibuang, karena jika tidak, extension tersebut akan tetap aktif di semua halaman github.dev
  • VSCode desktop juga memiliki kerentanan yang sama, tetapi penyerang harus membujuk korban untuk meng-clone repositori dan membuka notebook yang berisi payload skrip webview
  • Jika webview yang dibuka korban memiliki XSS lain, maka di desktop hal itu pada praktiknya dapat berujung pada remote code execution penuh

Pertahanan dan faktor mitigasi

  • Jika belum pernah memakai github.dev sebelumnya, ada satu dialog yang harus diklik saat masuk ke situs, sehingga memberi kesempatan untuk keluar dari halaman serangan
  • Dengan menghapus cookie dan data situs lokal github.dev, dialog awal ini bisa muncul kembali
  • Di Chrome, data terkait domain dapat dihapus dengan menekan ikon di bilah URL lalu masuk ke Cookies and site data > Manage on-device site data
  • Jika pengguna sudah pernah melewati dialog github.dev dan belum membersihkan local storage browser, maka github.dev tidak memiliki perlindungan seperti token CSRF, sehingga tautan apa pun di internet dapat mengarahkan ke serangan ini
  • VSCode tidak hanya mengandalkan isolasi iframe, tetapi juga memakai Content Security Policy yang ketat dan DOMPurify
  • Karena pratinjau Markdown di halaman extension memakai script-src 'none' untuk mencegah eksekusi JavaScript arbitrer, dampak yang lebih besar berupa desktop 1-klik RCE hanya dari tautan extension berhasil diblokir

Latar belakang pengungkapan dan timeline

  • MSRC sebelumnya diam-diam memperbaiki laporan bug VSCode tanpa memberi kredit dan menandainya sebagai tidak berdampak keamanan
  • Laporan bug XSS VSCode terbaru dari Starlabs juga ditandai tidak memenuhi syarat dan memiliki tingkat keparahan rendah
  • Tim VSCode mungkin memang memerlukan lebih banyak waktu untuk menyeimbangkan UI/UX dan keamanan, tetapi pengungkapan penuh dipilih karena waktu dan upaya peneliti keamanan tidak seharusnya dianggap remeh
  • Pada 2 Juni 2026, satu jam sebelum publikasi, rencana pengungkapan diberitahukan ke kontak lama di bagian keamanan GitHub
  • Pada hari yang sama, kerentanan dipublikasikan dan juga didaftarkan di VSCode issue tracker

1 komentar

 
GN⁺ 3 jam lalu
Komentar Hacker News
  • Rangkuman yang bagus, dan kalau dilihat lebih luas, cukup disayangkan bahwa editor VSCode yang di-embed di web itu sendiri sudah login ke GitHub
    Terlepas dari ada tidaknya pertahanan berlapis, dosa asal itulah yang membuat permukaan serangannya jadi besar. Ini mirip dengan menaruh token GitHub API berhak penuh dalam bentuk plaintext di workstation agar bisa ditemukan paket NPM berbahaya
    Idealnya, browser IDE berjalan dengan cakupan izin sementara per repositori atau token yang hanya bisa pull/push untuk repositori tersebut, dan sama sekali tidak memiliki sesi web github.com. Jika butuh seluruh UI web GitHub, kembali saja ke github.com, sementara github.dev dibiarkan sebagai layanan repositori tunggal
    Namun itu tentu kurang nyaman bagi pengguna, sulit diimplementasikan, dan kemungkinan besar bertabrakan dengan asumsi-asumsi lama yang sudah tertanam di seluruh alat github.dev

    • Codespaces memang benar-benar melakukan itu. Tokennya hanya punya izin baca/tulis untuk repositori milik Codespace yang diaktifkan [1]
      github.dev juga perlu mempertimbangkan pendekatan ini dengan serius
      [1] https://orca.security/resources/blog/hacking-github-codespac...
    • Masalah paket NPM berbahaya tampaknya akan makin parah. Baru-baru ini saya melihat alat eksekusi AI seperti OpenCode mengunduh paket npm acak di latar belakang lalu menyebarkannya ke berbagai tempat di direktori home dan direktori proyek, tanpa memberi tahu atau bertanya kepada pengguna
      Yang lebih buruk, para pengembang pun tampaknya tidak terlalu peduli
    • Saat membuka repositori sendiri dalam keadaan login mungkin masih bisa diterima, tetapi saat membuka repositori milik akun lain seharusnya itu sama sekali tidak boleh terjadi. Dan shortcut keyboard webview juga perlu diperbaiki agar hanya mengizinkan key binding yang tidak berbahaya dan tidak diteruskan ke handler keydown mana pun
      Di desktop, mungkin lebih baik Electron mencegatnya langsung dan fitur ini dihapus, sedangkan di web rasanya memang harus dinonaktifkan secara bawaan
    • Dengan SSH key dan GitHub deploy key, kurang lebih bisa dibuat serupa. Saya tidak berani memastikan dari sisi keamanannya, tetapi saya sendiri belum pernah menyiapkan GitHub dengan akses ke semua repositori
      Saya juga tidak terlalu tahu apakah hosting Git lain punya fitur serupa
    • Mungkin pull dari repositori itu tetap diizinkan, tetapi push dilakukan bukan ke token melainkan hanya ke area staging tempat pengguna bisa melakukan push final
      Sejujurnya agen LLM juga seharusnya begitu. Membiarkan LLM melakukan push langsung terasa ceroboh
  • Yang membuat serangan ini sangat rumit adalah bahwa ekstensi VSCode dijalankan dengan tingkat kepercayaan yang sama seperti editornya sendiri, dan kebanyakan pengembang memasang puluhan ekstensi tanpa pernah meninjau izinnya
    Jika ada ekstensi berbahaya atau yang telah dibajak membocorkan token GitHub secara diam-diam, itu sulit diketahui tanpa pemantauan jaringan, dan ini menjadi alasan bahwa ekstensi seharusnya dijalankan dalam profil yang terisolasi

    • Bahkan dengan pemantauan jaringan pun, kalau eksfiltrasinya dilakukan ke GitHub sendiri, itu sangat sulit dicegah. Terutama jika tidak ada intersepsi SSL dan daftar izin URL yang sangat ketat
      Cara terbaik adalah keluar dari GitHub dan pindah ke GitLab/Forgejo internal yang di-host sendiri, lalu memblokir GitHub sepenuhnya
  • Saya baru-baru ini mengalami hal yang mirip. Token GitHub dan token Cloudflare saya dicuri
    Menurut saya, sekalipun keamanan ditangani dengan serius, jika waktunya cukup lama pada akhirnya kita tetap bisa kena. Yang terbaik adalah melakukan pemisahan dan mengendalikan cakupan dampaknya
    Jangan percaya siapa pun dan apa pun, gunakan OrbStack, dan selalu bekerja dengan asumsi bahwa token pada akhirnya akan bocor
    Alur kerja saya benar-benar hancur, tetapi untungnya pihak yang mengambil token itu tampaknya lebih mirip bot spam. Mereka membuat banyak halaman spam palsu dan mencoba menambang kripto
    Kesan yang paling membekas adalah rasa telah diterobos. Semoga semuanya berhati-hati

    • Saya penasaran apakah itu halaman seperti GitHub Pages. Apakah ada repositori yang dibuat di akun Anda? Saya juga penasaran bagaimana Anda tahu token Anda telah dicuri
  • Bagian tentang pengalaman buruk saat melaporkan bug VSCode ke MSRC lalu mereka diam-diam memperbaikinya begitu saja itu sangat khas MSRC. Sepertinya mereka sadar para peneliti toh tetap melapor gratis, jadi merasa tidak ada alasan untuk berubah

    • Bukan MSRC yang memperbaiki bug
      Saya tidak tahu detail spesifik kasus ini, tetapi dulu saya pernah mengelola program bug bounty lewat Bountysource dan HackerOne. Kadang laporan lebih dulu mengalir ke tim pengembang sebelum tim keamanan sempat mengevaluasinya sepenuhnya
      Pada titik itu pengembang bisa saja memperbaikinya diam-diam. Terkadang karena kekhawatiran, rasional atau tidak, bahwa jika dikaitkan dengan bug keamanan hal itu akan terlihat buruk bagi mereka atau memengaruhi peluang promosi. Akibatnya, saat tim keamanan mencoba mereproduksi, kerentanannya sudah hilang
      Dari sudut pandang MSRC, yang terlihat hanya bahwa langkah reproduksi yang diberikan sudah tidak berfungsi lagi. Riwayat bug internal atau apakah seseorang sudah menambalnya tidak terlihat. Jadi laporannya ditutup sebagai tidak valid, meskipun penemuan aslinya sah
    • Sudah lama status quo-nya begitu, lalu para peneliti keamanan yang merepotkan mulai menuntut imbalan alih-alih reputasi
  • Terima kasih karena pada dasarnya Anda menyumbangkan waktu yang dipakai untuk eksploit ini demi menunjukkan bahwa respons keamanan VS Code perlu diperbaiki. Anda sebenarnya bisa saja menyerah, tetapi masih tetap membantu

    • Saya tidak berniat menjual atau menyimpan kerentanan ini. Hanya saja, membuat proof of concept bisa memakan beberapa jam, dan kalau vendornya cuma patch diam-diam tanpa memberi kredit maupun pengakuan, rasanya memang sangat menjengkelkan
  • Saya benar-benar tidak paham kenapa lebih banyak developer tidak mencoba Neovim
    Mungkin ini soal selera, tetapi saya suka konfigurasi kecil yang memungkinkan kita memahami apa yang terpasang dan apa yang sedang berjalan. Saat VSCode, browser IDE, ekstensi, sinkronisasi, token, dan plugin acak bercampur, jadi sulit mengetahui apa mengakses apa

    • Beberapa tahun lalu saya berhenti memakai VS Code dan pindah ke Neovim. Itu setelah saya tahu bahwa VS Code otomatis memasang paket Python acak untuk library yang tidak memiliki definisi tipe bawaan
      Itu adalah fitur dari ekstensi Python resmi Microsoft, dan dalam hal lain itu satu-satunya ekstensi yang lumayan layak dipakai, tetapi ia memasang definisi tipe untuk versi library yang berbeda dari versi yang dipakai proyek saya. Itu terasa sangat mengkhawatirkan karena tampak seperti dengan santainya menjalankan kode pihak ketiga yang tidak diverifikasi, dan sepertinya juga tidak bisa dimatikan lewat pengaturan
      Saya ingin bilang “sejak itu saya tidak pernah menoleh ke belakang”, tetapi sejujurnya selama 1~2 tahun terakhir Neovim mulai rutin merusak konfigurasi saya hampir di setiap upgrade. Sebenarnya tanda-tandanya sudah ada. Secara teknis sudah 10 tahun berlalu, tetapi nvim masih belum merilis versi stabil pertamanya, jadi kita tidak bisa benar-benar menyalahkan ketidakstabilannya, namun itu patut diingat
      Saya sedang mempertimbangkan kembali ke Vim murni. Saya akan kehilangan banyak fitur kenyamanan, tetapi saya ingin lebih jarang harus men-debug fitur yang rusak saat sedang bekerja
    • Saya cukup suka Helix. Saya memang belum mendalami Neovim, tetapi Helix punya cukup banyak fitur ala IDE yang selama ini selalu terasa kurang di Vim
      Tidak perlu memasang banyak plugin atau memakai sesuatu seperti SpaceVim. Mungkin Anda akan suka kalau mencobanya
    • Saya merasa cukup sulit membuat orang mengubah kebiasaan software mereka. Ada shortcut yang harus dipelajari, dan pada awalnya terasa lebih lambat sehingga memperkuat kesan bahwa itu “tidak lebih baik”
      Perlu waktu untuk terbiasa dengan nvim, tetapi setelah terbiasa, ia lebih cepat. Tetap saja, ini menjelaskan kenapa banyak orang bertahan di zona nyaman mereka
  • Pengungkapan publik adalah langkah yang tepat. Terlalu banyak orang punya keluhan terhadap MSRC, dan seperti situasi Nightmare Eclipse, sekarang rasanya mulai meluap
    Jika pengungkapan seperti ini terus menumpuk, mungkin MSRC akan bercermin dan sadar bahwa merekalah masalahnya. Kemungkinannya tampak kecil, tetapi kita masih boleh berharap

    • Saya masih tidak yakin apakah ini pendekatan terbaik. Sepertinya dia bahkan tidak mencoba mengirimkannya karena memperkirakan akan diberi rating “rendah” dibanding submission XSS sebelumnya
      Meski begitu, menurut saya setidaknya ia seharusnya mencoba, atau memberi tahu beberapa hari sebelum dipublikasikan. Kita tidak pernah tahu apa yang akan terjadi
  • Tulisannya sangat bagus, tetapi bagian akhir agak membingungkan buat saya. Saya ingin memastikan apakah pemahaman saya benar
    Penulis mengatakan bahwa karena sistem kepercayaan publisher yang baru, ekstensi berbahaya tidak bisa dipasang langsung hanya dengan trik shortcut, dan bahwa ini bisa dilewati dengan ekstensi workspace lokal yang tidak memiliki pemeriksaan publisher, tetapi CSP memblokirnya
    Solusinya tampaknya adalah memasang ekstensi workspace lokal yang membinding shortcut “install extension tanpa verifikasi publisher”
    Jadi saya penasaran apakah 1) ini berarti dibutuhkan dua ekstensi. Yang pertama adalah ekstensi lokal yang hanya melakukan key binding, dan yang kedua adalah ekstensi berbahaya yang sebenarnya, yang karena CSP tidak perlu lokal dan pada praktiknya juga tidak bisa lokal, dan 2) apakah CSP hanya memblokir JS dari ekstensi lokal, tetapi tidak memblokir package.json atau kemampuan menambahkan shortcut

    • 1 dan 2 benar. Lihat saja repositori proof-of-concept: https://github.com/ammaraskar/github-dev-token-steal-poc/tre...
      Untuk eksekusi paling langsung, Anda bisa mencoba memasukkan my-extension/extension.js, tetapi itu diblokir oleh CSP. Namun karena script-src CSP hanya memblokir skrip, mengambil package.json tetap diizinkan. Jadi itu dimanfaatkan untuk menambahkan key binding
  • Situasi MSRC benar-benar sulit dipercaya
    Mungkin ada materi yang lebih baik, tetapi saya rasa video The Primeagen ini adalah bahan pengantar yang bagus
    https://www.youtube.com/watch?v=9kxx5xp5nTQ

  • Saya punya sedikit nitpick pada bagian “Satu-satunya cara untuk mengizinkan perilaku ini adalah dua halaman web dari origin berbeda bekerja sama melalui API Window.postMessage()
    iframe atau jendela induk juga bisa berkomunikasi dengan mengubah properti location.anchor