Roubo de token do GitHub com 1 clique por meio de bug no VSCode
(blog.ammaraskar.com)- github.dev usa um token OAuth repassado por github.com para abrir arquivos, enviar PRs e fazer commits no VSCode no navegador, e como esse token não é limitado a um repositório específico, ele pode ler e escrever em todos os repositórios aos quais o usuário tem acesso
- O webview do VSCode é isolado em um iframe
vscode-webview://..., mas, por causa da UX de atalhos de teclado, okeydowndo webview é encaminhado para a janela principal como uma mensagemdid-keydown, permitindo que scripts não confiáveis enviem eventos como se fossem entradas do usuário - A entrada de texto arbitrária não funciona por causa do HTML
<input>, mas é possível executar o comando de instalação de extensão combinando o atalho padrãoCtrl+Shift+A, a notificação de instalação de extensão recomendada, local workspace extensions e keybindings personalizados - O PoC executa JavaScript em uma célula Markdown de um Jupyter notebook para aceitar a instalação da extensão recomendada, instalar a extensão escolhida com um novo keybinding e então exibir o token da API do GitHub e a lista de repositórios privados
- O VSCode desktop também tem a mesma vulnerabilidade, mas o atacante precisa induzir a clonagem do repositório e a abertura do notebook; usuários do github.dev precisam limpar os dados do site para que a caixa de diálogo inicial de confirmação volte a aparecer
Visão geral da vulnerabilidade
- O github.dev abre uma versão leve do VSCode executada no navegador quando se troca a URL de um repositório GitHub acessível de
github.comparagithub.devou se clica em um item de menu - Esse VSCode no navegador pode visualizar arquivos do repositório, abrir repositórios privados e também enviar PRs e criar commits
- O github.com envia por POST para o github.dev um token OAuth capaz de interagir com o GitHub em nome do usuário, e esse token não é restrito ao repositório específico com o qual o usuário interagiu
- Um atacante pode roubar um token do GitHub com permissões de leitura e escrita apenas com um clique em um link, e o alcance inclui repositórios privados
Isolamento de Webview e problema no encaminhamento de teclas
- Os webviews do VSCode usam um
<iframe>de origem diferente da janela principal do VSCode para isolar a execução de JavaScript - A saída de notebooks Jupyter é renderizada em um
<iframe>com origemvscode-webview://..., enquanto a janela principal do Electron usa a origemvscode-file://... - Graças a esse isolamento, mesmo que o notebook use exibição em HTML ou widgets interativos baseados em JavaScript, ele não consegue chamar as APIs Node.js do Electron nem a API do VSCode de dentro do iframe
- Recursos que exigem cooperação entre a janela principal e o webview, como a pré-visualização de Markdown, trocam mensagens por meio da API Window.postMessage()
- O VSCode encaminha eventos
did-keydownpara a janela principal para que atalhos comoCtrl+Shift+Pfuncionem mesmo quando o foco está dentro do webview - Scripts não confiáveis dentro do webview podem disparar diretamente eventos
keydowne se passar pelo usuário pressionando teclas
Cadeia de ataque
- É possível abrir a paleta de comandos com
Ctrl+Shift+P, mas como ela usa um HTML<input>, a técnica de inserir texto arbitrário não funciona - Entradas tratadas como
keydown, como setas direcionais eEnter, podem ser usadas, assim como o conjunto padrão de atalhos do VSCode Ctrl+Shift+Aé o keybinding padrão de “Notifications: Accept Notification Primary Action” e aciona o botão principal da última notificação do VSCode- Se houver extensões recomendadas em
.vscode/extensions.json, o VSCode mostra uma notificação para instalação, mas o sistema de confiança de publicador do VSCode 1.97 exibe uma caixa de diálogo separada ao instalar uma extensão de um novo publicador - Dá para mover entre botões com
Tab, mas como o tratamento deEnterdo botão “Trust Publisher & Install” está preso aokeydowndo próprio botão, é difícil concluir a instalação só por esse caminho - local workspace extensions permitem instalar diretamente extensões presentes em
.vscode/extensionsdentro de um workspace confiável, e workspaces web do github.dev estão sempre em estado confiável - Se tentar executar diretamente uma extensão local do workspace, o worker de extensões espera uma extensão vinda de
vscode-cdn.net, gerando um erro de CSP - Em vez disso, é possível adicionar um keybinding personalizado no
package.jsonda extensão local do workspace para que esse keybinding invoqueworkbench.extensions.installExtensioncom o contextoskipPublisherTrust
Funcionamento do PoC e impacto
- A configuração necessária é um repositório com um Jupyter notebook e uma local workspace extension
- A célula Markdown do notebook pode executar JavaScript por meio do atributo
onerrorde uma imagem - O payload espera até que o VSCode mostre a notificação de instalação da extensão recomendada e então envia um evento
Ctrl+Shift+Apara aceitar a ação principal da notificação - Depois, espera a extensão ser instalada e ativada e o keybinding personalizado ficar disponível, e então dispara
Ctrl+F1para acionar a instalação da extensão escolhida - A extensão instalada no PoC obtém o token da API do GitHub, consulta
https://api.github.com/user/repospara recuperar os repositórios privados acessíveis e então mostra o token e a lista de repositórios em uma caixa de informação - Após executar o PoC, é preciso limpar os dados do github.dev ou remover a extensão do PoC; se ela não for removida, continuará presente em todas as páginas do github.dev
- O VSCode desktop também é afetado pela mesma vulnerabilidade, mas o atacante precisa convencer a vítima a clonar o repositório e abrir o notebook com o payload de script no webview
- Se o webview aberto pela vítima tiver outro XSS, isso pode na prática evoluir para execução remota de código quase total também no desktop
Defesa e fatores de mitigação
- Se você nunca usou o github.dev antes, existe uma caixa de diálogo inicial que precisa ser clicada ao entrar no site, criando uma chance de sair da página de ataque
- Ao limpar os cookies e os dados locais do site do github.dev, essa caixa de diálogo inicial pode voltar a aparecer
- No Chrome, é possível clicar no ícone da barra de endereço e ir em Cookies and site data > Manage on-device site data para remover os dados dos domínios relacionados
- Se o usuário já passou pela caixa de diálogo do github.dev e não limpou o armazenamento local do navegador, o github.dev não tem proteções como token CSRF, então qualquer link na internet pode redirecionar para o ataque
- O VSCode não depende apenas do isolamento por iframe e também usa uma Content Security Policy rígida e o DOMPurify
- Como a pré-visualização de Markdown da página de extensões usa
script-src 'none'para impedir execução arbitrária de JavaScript, o impacto maior de um RCE desktop com 1 clique apenas por um link de extensão acaba bloqueado
Contexto da divulgação e cronograma
- O MSRC no passado corrigiu silenciosamente relatos de bugs do VSCode sem dar crédito e os marcou como sem impacto de segurança
- Um relato recente do bug de XSS no VSCode da Starlabs também foi marcado como inelegível e de baixa severidade
- Pode ser que a equipe do VSCode precisasse de mais tempo para equilibrar UI/UX e segurança, mas a divulgação completa foi escolhida porque o tempo e o esforço de pesquisadores de segurança não devem ser tratados como algo garantido
- A divulgação planejada foi informada uma hora antes da publicação, em 2 de junho de 2026, para um contato existente da equipe de segurança do GitHub
- A vulnerabilidade foi publicada no mesmo dia e também registrada no issue tracker do VSCode
1 comentários
Comentários do Hacker News
Foi um bom resumo e, no panorama geral, é lamentável o próprio fato de o editor VSCode embutido na web estar logado no GitHub
Independentemente de haver defesa em profundidade, esse pecado original já cria uma superfície de ataque enorme. É parecido com deixar em texto puro na workstation um token da API do GitHub com todas as permissões, para qualquer pacote NPM malicioso conseguir encontrar
No cenário ideal, a IDE no navegador rodaria com um escopo temporário por repositório ou um token que só permitisse pull/push naquele repositório, e não teria nenhuma sessão web do github.com. Se precisar da UI web completa do GitHub, volta para o github.com, e o github.dev fica como um serviço de repositório único
Mas isso seria incômodo para o usuário, difícil de implementar, e provavelmente entra em conflito com premissas históricas espalhadas por todo o ferramental do github.dev
O github.dev também deveria considerar seriamente essa abordagem
[1] https://orca.security/resources/blog/hacking-github-codespac...
O pior é que parece que até os próprios desenvolvedores não ligam muito para isso
keydownNo desktop, parece melhor fazer o Electron interceptar isso diretamente e remover esse recurso; na web, o certo seria deixar desativado por padrão
Também não sei se outros hostings Git têm algo parecido
Sinceramente, agentes com LLM também deveriam funcionar assim. Deixar o LLM fazer push direto parece imprudente
O que torna esse ataque especialmente complicado é que extensões do VSCode rodam com o mesmo nível de confiança do próprio editor, e a maioria dos desenvolvedores instala dezenas de extensões sem revisar permissões
Se uma extensão maliciosa ou comprometida vazar silenciosamente o token do GitHub, é difícil perceber sem monitoramento de rede, o que reforça a ideia de que extensões deveriam rodar em perfis isolados
O melhor caminho é sair do GitHub e migrar para um GitLab/Forgejo interno self-hosted, bloqueando completamente o GitHub
Recentemente passei por algo parecido. Roubaram meu token do GitHub e meu token da Cloudflare
Acho que, por mais a sério que se leve segurança, se o tempo for longo o bastante, uma hora você vai ser atingido. O melhor é isolar e controlar o alcance do dano
Não confie em ninguém nem em nada, use OrbStack e sempre trabalhe assumindo que seus tokens vão vazar algum dia
Meu fluxo de trabalho foi completamente interrompido, mas felizmente quem pegou os tokens parecia mais um bot de spam. Criaram um monte de páginas falsas de spam e tentaram minerar criptomoeda
O sentimento que mais fica é o de violação. Tomem cuidado
A parte sobre ter reportado o bug do VSCode ao MSRC e eles simplesmente corrigirem em silêncio foi uma experiência horrível bem típica do MSRC. Parece que perceberam que os pesquisadores vão reportar de graça de qualquer jeito, então não veem motivo para mudar
Não conheço os detalhes específicos deste caso, mas no passado já administrei programas de bug bounty via Bountysource e HackerOne. Às vezes, antes de a equipe de segurança terminar a avaliação, o relatório acaba chegando primeiro à equipe de desenvolvimento
Nesse ponto, o desenvolvedor pode corrigir em silêncio. Às vezes por receio, racional ou não, de que, por estar associado a um bug de segurança, isso fique mal para ele ou afete chances de promoção. O resultado é que, quando a equipe de segurança vai tentar reproduzir, a vulnerabilidade já desapareceu
Do ponto de vista do MSRC, eles só veem que os passos de reprodução fornecidos já não funcionam mais. Não têm visibilidade do histórico interno do bug nem de que alguém já aplicou um patch. Então o relatório é encerrado como inválido, mesmo que a descoberta original tenha sido legítima
Obrigado por praticamente doar o tempo gasto neste exploit e, com isso, mostrar a necessidade de melhorar a resposta de segurança do VS Code. Você poderia simplesmente ter desistido, mas continua ajudando
Não entendo muito bem por que mais desenvolvedores não tentam usar Neovim
Pode ser questão de preferência, mas gosto de uma configuração pequena em que dá para entender o que está instalado e o que está em execução. Quando VSCode, IDE no navegador, extensões, sincronização, tokens e plugins aleatórios se misturam, fica difícil saber o que tem acesso a quê
Era um recurso da extensão oficial de Python da Microsoft e, em outros aspectos, era a única extensão minimamente utilizável, mas ela instalou definições de tipos para uma versão da biblioteca diferente da usada pelo meu projeto. Parecia estar executando código de terceiros não verificado com a maior naturalidade, o que me deixou muito desconfortável, e não parecia haver nem como desativar isso nas configurações
Eu gostaria de dizer que “nunca mais olhei para trás”, mas, sinceramente, nos últimos 1~2 anos o Neovim começou a quebrar minha configuração regularmente em quase todo upgrade. Já dava para sentir que isso poderia acontecer um dia. Tecnicamente, já se passaram 10 anos, mas o nvim ainda não lançou sua primeira versão estável, então não dá para culpar a instabilidade, mas é algo a se ter em mente
Estou pensando em voltar para o Vim puro. Vou perder muitos recursos de conveniência, mas queria pelo menos reduzir as vezes em que preciso depurar funcionalidades quebradas no meio do trabalho
Não precisa instalar um monte de plugins nem usar algo como SpaceVim. Talvez valha a pena dar uma olhada, pode ser que você goste
Leva tempo para se acostumar com o nvim, mas, depois que você se acostuma, ele fica mais rápido. Ainda assim, dá para entender por que tanta gente permanece na zona de conforto
Tornar isso público publicamente foi uma boa decisão. Muita gente está insatisfeita com o MSRC, e isso agora começa a transbordar, como no caso Nightmare Eclipse
Se divulgações assim se acumularem, talvez o MSRC faça uma autocrítica e perceba que ele mesmo é o problema. Parece improvável, mas dá para ter esperança
Mesmo assim, acho que ele deveria ao menos ter tentado, ou avisado alguns dias antes de publicar. Nunca se sabe o que pode acontecer
O texto foi muito bom, mas fiquei um pouco confuso na parte final. Quero confirmar se entendi certo
O autor disse que, por causa do novo sistema de confiança de publicador, não é possível instalar diretamente uma extensão maliciosa só com o truque de atalhos, e que isso pode ser contornado com uma extensão local de workspace, que não passa por verificação de publicador, mas que o CSP bloqueia
A solução parece ser instalar uma extensão local de workspace que vincula um atalho para “instalar extensão sem verificação de publicador”
Então, 1) isso quer dizer que são necessárias duas extensões? A primeira seria uma extensão local que só faz o keybinding, e a segunda seria a extensão realmente maliciosa, que por causa do CSP nem precisa ser local e, na prática, nem pode ser local? E 2) o CSP só bloqueia o JS da extensão local, mas não bloqueia o
package.jsonnem a capacidade de adicionar atalhos?Você pode tentar colocar
my-extension/extension.jspara a execução mais direta, mas o CSP bloqueia. Porém, como oscript-srcdo CSP bloqueia apenas scripts, buscar opackage.jsoncontinua permitido. Então isso é usado para contribuir com o keybindingA situação do MSRC é realmente inacreditável
Pode haver materiais melhores, mas acho que este vídeo do The Primeagen é um bom material de introdução
https://www.youtube.com/watch?v=9kxx5xp5nTQ
Tenho uma pequena implicância com a parte que diz “a única maneira de permitir esse comportamento é duas páginas web de origens diferentes cooperarem via a API
Window.postMessage()”Também dá para se comunicar fazendo o iframe ou a janela pai alterarem a propriedade
location.anchor