Modelo de segurança: o que o sim faz diante de cada ameaça

O sim foi construído em torno de uma pergunta: o que um arquivo, uma pasta ou um repositório que você não escreveu pode fazer com você? Esta página apresenta o modelo de ameaças e o que o sim faz diante de cada uma.

Modelo de ameaças

Você abre arquivos e repositórios que não escreveu: um clone, um arquivo compactado extraído, um checkout de pull request, um arquivo gravado por outro processo. O atacante controla o conteúdo deles, não a sua máquina. O sim procura garantir que esse conteúdo não consiga se esconder de você, não consiga reconfigurar o editor e não consiga fazer o editor executar código.

Premissas

  • Você confia no seu próprio terminal, na sua própria conta de usuário e na sua própria configuração global do git.
  • O atacante pode alterar qualquer arquivo de um repositório, inclusive .git/config e os arquivos que ficam ao lado do que você abre.
  • O atacante não pode alterar o próprio sim nem o seu diretório home.

Ameaças e o que o sim faz

  • Caracteres de controle bidirecionais (Trojan Source)

    A ameaça

    Controles Unicode reordenam a forma como o código é exibido, de modo que o código que um revisor lê não é o código que o compilador lê (CVE-2021-42574). O conselho dos pesquisadores aos editores é tornar esses caracteres perceptíveis.[1] [2] [3]

    O que o sim faz

    U+200E–200F, U+202A–202E, U+2066–2069 e U+061C são desenhados como <U+202E> sobre um bloco magenta e nunca são enviados crus ao terminal. O bloco vale em qualquer estado em que uma célula possa estar: selecionada, encontrada por uma busca, na linha do cursor, dentro de uma mudança vinda de fora, na névoa de uma linha distante, em um título ou em um bloco de código. O texto literal <U+202E> digitado em um arquivo é texto comum e não recebe bloco.

    Especificação: SAFE-8, UI-15

  • Caracteres invisíveis e espaços

    A ameaça

    Muitos caracteres Unicode não desenham nada. Uma sequência de caracteres de etiqueta, que espelham o ASCII, pode levar uma instrução escondida a um assistente de IA que lê o arquivo (“ASCII smuggling”); segundo o próprio padrão, um renderizador que desconhece as etiquetas vai “display any sequence of tag characters as invisible” (exibir qualquer sequência de caracteres de etiqueta como invisível). Uma sequência de seletores de variação pode levar um programa: um escondeu uma carga em extensões publicadas do VS Code (GlassWorm). Preenchimentos, hifens suaves, uniões e separadores de linha podem ficar dentro de um identificador ou de um comentário sem mudar nada do que você vê. Um espaço de largura zero, uma marca de ordem de bytes no meio de um arquivo, um espaço não separável ou espaços no fim da linha mudam o que um arquivo significa, ou como um diff é lido, do mesmo jeito.[4] [5] [6] [7] [8] [9]

    O que o sim faz

    U+200B, e U+FEFF em qualquer lugar que não seja o início do arquivo, são desenhados como <U+200B> e <U+FEFF>. Um espaço não separável é desenhado como ⍽, espaços no fim da linha como · e tabulações como ».

    Todo caractere que não desenha nada é mostrado do mesmo modo, como <U+E0041> sobre o bloco magenta, no texto, na linha de status, nas mensagens e na linha de comando, e nos nomes e linhas que vêm de arquivos (a árvore, as abas, a trilha de navegação e os resultados de busca): caracteres de formatação, caracteres de etiqueta, seletores de variação, preenchimentos hangul, o hífen suave, o unidor de grafemas combinantes, U+2028 e U+2029, e todo ponto de código que o Unicode 18.0.0 deixa sem atribuir. Estes ficam como estão: um unidor de largura zero entre dois emoji, um seletor de variação depois de um pictograma, as três bandeiras da Inglaterra, da Escócia e do País de Gales e os caracteres de uso privado (os ícones de uma Nerd Font); os mesmos caracteres em qualquer outro lugar são mostrados. O custo: um kanji seguido de um seletor de variação ideográfica (um modo registrado de escolher uma forma de glifo de um kanji) mostra o seletor, 葛<U+E0100>, porque o mesmo caractere é um canal para esconder dados; isso recai principalmente sobre o texto japonês. A orientação do Unicode para editores de código-fonte recomenda “an option to make visible any default ignorable code points” (uma opção para tornar visíveis os pontos de código ignoráveis por padrão); o sim não tem essa opção e sempre os mostra.[10] [6] [11] [12] [13]

    Especificação: SAFE-8, SAFE-10, SAFE-11, UI-6

  • Sequências de escape do terminal em arquivos e nomes de arquivo

    A ameaça

    Caracteres de controle em um arquivo, ou em um nome de arquivo, podem chegar ao terminal como sequências de escape.

    O que o sim faz

    Caracteres C0 e DEL são desenhados como ^[ e os C1 como <U+0085>. Nada cru é escrito no terminal, e os testes verificam os bytes enviados.

    Caracteres de controle e bidirecionais em nomes de arquivo são desenhados com as mesmas formas, ^[ e <U+202E>, na árvore, nas abas, na trilha de navegação, nos resultados de busca e no seletor; a v0.1.0 os desenhava como U+FFFD.

    Especificação: SAFE-8, SAFE-10, TREE-1, GREP-7

  • Configurações escondidas em um arquivo (modelines)

    A ameaça

    Um comentário em um arquivo pode definir opções do editor, e bugs nesse mecanismo já levaram à execução de código: CVE-2019-12735 (Vim e Neovim) e CVE-2026-34982 (Vim).[14] [15] [16]

    O que o sim faz

    Configurações e comandos nunca são lidos do conteúdo de arquivos. Não existe modeline para contornar.

    Especificação: SAFE-9

  • Configuração local do projeto

    A ameaça

    Um diretório de projeto pode carregar uma configuração que um editor carrega e executa: arquivos exrc no Vim e no Neovim, .helix/config.toml no Helix.[17] [18] [19]

    O que o sim faz

    O sim não tem arquivos de configuração, plugins nem configuração local de projeto para carregar. Apenas a sua escolha de aparência, de ícones e de visualização de Markdown é memorizada, como uma palavra para cada, no diretório de estado do sim.

    Especificação: SAFE-9, LOOK-1

  • Configuração de repositório que executa comandos

    A ameaça

    O git executa comandos citados no .git/config do próprio repositório. core.fsmonitor indica um hook que comandos do git como git status invocam, e um driver de filtro indica programas que rodam sobre o conteúdo de um arquivo. Um editor que pergunta ao git o status de um repositório que você acabou de extrair pode executá-los.[20] [21] [22]

    O que o sim faz

    O sim primeiro pergunta ao git a configuração do repositório. O que uma linha de comando consegue impedir é desligado (core.fsmonitor, hooks, filtros, um diff externo, uma conversão de texto), e o git responde. Se os escopos próprios do repositório definirem qualquer outra coisa que possa conter um comando (core.sshCommand, um include que poderia trazer um), o git não é executado. Quando roda, é sem shell, com --no-optional-locks e com um ambiente que impede qualquer busca. O sim não executa nenhum comando de escrita do git, então nenhum hook roda. A árvore diz n git settings off ou git not run, e a linha de status indica a chave e onde ela está.

    Especificação: MARK-1, GIT-1, GIT-2, GIT-3, GIT-5

  • Arquivos reescritos de fora

    A ameaça

    Uma compilação, um formatador ou uma ferramenta reescreve o arquivo que você tem aberto. Ao salvar, você sobrescreve o trabalho dela, ou o trabalho dela sobrescreve o seu.

    O que o sim faz

    O sim percebe, marca o que mudou e compara o hash do arquivo com o do momento do carregamento logo antes do rename. Se forem diferentes, nada é gravado.

    Uma mudança que chega enquanto um salvamento está sendo escrito agora espera a resposta do salvamento, então não pode ser mesclada sobre o texto que está sendo salvo. Uma condição de corrida rara, encontrada em 2026-10-18, podia perder uma linha na v0.1.0.

    Especificação: DISK-1, DISK-2, SAFE-5, SAFE-7

  • Falhas e terminais fechados

    A ameaça

    Uma falha, um kill -9 ou um terminal fechado faz perder o texto não salvo.

    O que o sim faz

    O texto não salvo ganha um snapshot no máximo uma vez por segundo em um diretório de estado privado e é oferecido de volta como um único passo de desfazer. O diretório precisa ser um diretório de verdade, pertencer a você e não dar acesso a outros; caso contrário, os snapshots ficam desligados e o sim avisa.

    Especificação: SAFE-6

  • Arquivos que não são texto

    A ameaça

    Conteúdo binário ou que não é UTF-8, exibido como se fosse texto, pode esconder o que o arquivo contém e ser corrompido por um salvamento.

    O que o sim faz

    Esses arquivos abrem somente para leitura, com o motivo à mostra. Bytes inválidos são desenhados como U+FFFD, e todo tipo de gravação é recusado.

    Especificação: SAFE-4

O que o sim não faz

  • O sim não é um sandbox. Ele roda com os seus privilégios. Mostrar um caractere oculto não impede você de executar o código que ele esconde.
  • A lista de caracteres é fixa: a tabela do Unicode 18.0.0. Um ponto de código que uma versão posterior atribua é mostrado como oculto até a tabela ser refeita. Não é uma verificação completa dos confundíveis do Unicode (UTR #36), e letras parecidas de outros sistemas de escrita (homóglifos, a outra metade do Trojan Source) não fazem parte do que a documentação descreve.
  • A última verificação antes de salvar compara a marca do arquivo e só compara o hash se a marca mudou. Uma escrita no mesmo microssegundo, ou uma reescrita do mesmo tamanho dentro de um tique de carimbo de tempo num sistema de arquivos de carimbos grosseiros, ainda pode passar.
  • Tudo nesta página vem da especificação e dos testes do próprio projeto. Nenhuma auditoria independente é citada na documentação.
  • O suporte a servidores de linguagem ainda não existe. Um cliente em sandbox está no roadmap abaixo.

Roadmap: servidores de linguagem

Planejado

Um servidor de linguagem é um programa que um projeto pode pedir ao seu editor para iniciar, o que o torna uma das maiores formas de um repositório executar código. O sim ainda não tem um. O plano é um cliente em sandbox e um indicador, na linha de status, de se a raiz do projeto é confiável. Está planejado, não lançado.

Fontes

  1. NVD: CVE-2021-42574 (bidirectional control characters, “Trojan Source”)
  2. Boucher and Anderson, Trojan Source: Invisible Vulnerabilities (USENIX Security 2023)
  3. Unicode Standard Annex #9: Unicode Bidirectional Algorithm
  4. Unicode Technical Report #36: Unicode Security Considerations
  5. Johann Rehberger, ASCII Smuggler Tool: Crafting Invisible Text and Decoding Hidden Codes (Embrace The Red, 14 January 2024)
  6. Unicode Technical Standard #51: Unicode Emoji, revision 31 (ZWJ sequences, emoji tag sequences, Annex C)
  7. Paul Butler, Smuggling arbitrary data through an emoji (8 February 2025)
  8. Koi Security, GlassWorm: First Self-Propagating Worm Using Invisible Code Hits OpenVSX Marketplace (18 October 2025; the original address now redirects elsewhere, so this is the Internet Archive's copy)
  9. Endor Labs, Invisible Threats and the Blind Spots of Security (an analysis of GlassWorm)
  10. The Unicode Standard 18.0, chapter 23, Special Areas and Format Characters (§23.4 Variation Selectors, §23.9 Tag Characters)
  11. Unicode Technical Standard #55: Unicode Source Code Handling, revision 5 (§4.2 Blank and Invisible Characters)
  12. Unicode Technical Standard #37: Unicode Ideographic Variation Database, revision 16 (ideographic variation sequences)
  13. Unicode Ideographic Variation Database: the registered collections (Adobe-Japan1, Hanyo-Denshi, Moji_Joho and others)
  14. NVD: CVE-2019-12735 (Vim before 8.1.1365 and Neovim before 0.3.6, modeline)
  15. NVD: CVE-2026-34982 (Vim before 9.2.0276, modeline sandbox bypass)
  16. Vim security advisory GHSA-8h6p-m6gr-mpw9 (modeline sandbox bypass)
  17. Vim 9.2.1202, runtime/doc/options.txt ('modeline', 'modelinestrict', 'exrc', 'isprint', 'fsync')
  18. Neovim 0.12.6, runtime/doc/options.txt ('modeline', 'modelineexpr', 'exrc', 'isprint', 'fsync')
  19. Helix 25.07.1, book/src/configuration.md (a config.toml local to a project)
  20. git-config documentation (core.fsmonitor, filter.<driver>.*)
  21. githooks documentation (fsmonitor-watchman, post-index-change)
  22. Justin Steven, Git honours embedded bare repos, and exploitation via core.fsmonitor affects IDEs (2022)
  23. ripgrep user guide (the config file named by RIPGREP_CONFIG_PATH, --pre)