FlawOpen

flawopen.com/Teardowns/cve-2026-102437-deepseek-reasonix-git-filter-command-injection

● CVE-2026-102437 · CVSS 7.8[2] · Alta
Pesquisa · FlawOpen

CVE-2026-102437: injeção Git ao ver diff no Reasonix

Um par malicioso .gitattributes/.git/config pode executar um filtro clean ao abrir diff no Reasonix. Atualize npm 1.39.3 ou Studio 2.21.0.[1], [2], [3], [6], [7]

💡 Explicação em Linguagem Simples (ELI5)

Imagine uma mesa de triagem que promete apenas comparar duas etiquetas. Um pacote pode trazer uma instrução de roteamento que manda a mesa executar um auxiliar registrado antes de comparar o conteúdo. O Reasonix desativava alguns auxiliares do Git, mas o filtro clean por arquivo era outro caminho. Quando a tela de diff pedia ao Git que preparasse o arquivo, esse filtro podia rodar com as permissões do desenvolvedor.[1], [3]

Conceitos Centrais e Termos

Filtro clean do Git
Transformação configurada que o Git pode executar para converter o conteúdo de um arquivo da árvore de trabalho para a forma armazenada no repositório.[1], [3]
.gitattributes
Arquivo versionado no repositório que pode atribuir um filtro nomeado a determinados caminhos.[1]
.git/config
Configuração local do repositório que pode definir o comando chamado por um filtro. Um clone normal não copia esse arquivo local.[1], [3]
Visualizador de diff
Recurso que pede ao Git que prepare e compare o conteúdo de trabalho de um arquivo com o conteúdo confirmado no repositório.[1]

Mapeamentos de frameworks

  • Referência CWE para a fraqueza descrita neste guia: CWE-78

Análise de Causa Raiz

O Reasonix reforçava chamadas git diff com --no-ext-diff e --no-textconv , mas essas opções controlam mecanismos de diff externo e conversão de texto; elas não desativam os filtros clean de conteúdo do Git. A visualização de alterações do workspace chamava git diff para um caminho selecionado. Se o conteúdo do repositório atribuísse um filtro ao caminho via .gitattributes e a configuração local do Git definisse o comando desse driver, o Git poderia executá-lo ao construir o blob de comparação. O CVE descreve um atacante local e exige interação do usuário para abrir o diff. A divulgação do GitLab informa que um clone comum não transfere .git/config ; arquivos compactados, diretórios sincronizados, caches ou devcontainers preparados podem incluí-lo. Também descreve um agente local com as mesmas permissões que pode gravar configuração local no repositório. O impacto é execução de comandos com as permissões do usuário do Reasonix, não execução remota apenas por abrir um repositório hospedado no GitLab.[1], [3]

Fluxo de Ataque Passo a Paso

Passo 1

O workspace recebe estado de repositório não confiável

O desenvolvedor abre um projeto cujos atributos versionados associam um arquivo a um filtro e cuja configuração Git local define esse filtro. O aviso do mantenedor exige os dois elementos; um clone normal, sozinho, não fornece a configuração local.[1], [3]

Passo 2

O desenvolvedor solicita um diff

A visualização de alterações do Reasonix executa o caminho de diff do Git para o arquivo selecionado. Essa ação na interface é a interação exigida pelo CVE.[1], [3]

Passo 3

O Git aplica o caminho do filtro clean

O Git prepara o conteúdo para comparação e pode chamar o filtro clean configurado. --no-ext-diff e --no-textconv desativam mecanismos diferentes e não suprimem esse filtro.[1], [3]

Passo 4

O filtro roda com as permissões do usuário

O comando configurado para o filtro é executado no contexto do processo do Reasonix. A consequência documentada é execução local de comandos com as permissões desse usuário.[1], [2], [3]

Código-Fonte: Vulnerável vs. Seguro

Este auxiliar de argumentos é ilustrativo, não um patch pronto para uso. O chamador deve enumerar todos os drivers selecionados por .gitattributes, .git/info/attributes e arquivos de atributos globais/do sistema, definindo discoveryComplete somente após uma varredura completa bem-sucedida. Esta função valida os nomes fornecidos e gera substituições de configuração na linha de comando; ela não descobre nem verifica o conjunto de drivers. A chamada vulnerável foi citada na divulgação do GitLab; o padrão defensivo é uma síntese original das orientações dos mantenedores e dos PRs de hardening mesclados.[1], [3], [4], [5]

Trecho de origem: desktop/workspace_changes.go

IMPLEMENTAÇÃO VULNERÁVEL
// Chamada de origem citada pela GitLab Threat Research; é o ponto de chamada, não a função completa.
args := []string{"-C", base, "diff", "--no-ext-diff", "--no-textconv", "--relative", "HEAD", "--", filepath.FromSlash(rel)}
PATCH SEGURO E ROBUSTO
// Construtor ilustrativo de argumentos Go, não um patch literal do fornecedor.
package gitguard

import (
    "errors"
    "fmt"
    "path/filepath"
    "regexp"
)

// O chamador deve descobrir todos os filtros selecionados pelos atributos efetivos e passar o conjunto completo.
// Este auxiliar apenas neutraliza essas chaves de driver em todos os escopos de configuração do Git.
var filterDriverName = regexp.MustCompile(`^[A-Za-z0-9_-]{1,64}$`)

func hardenedDiffArgs(base, rel string, drivers []string, discoveryComplete bool) ([]string, error) {
    if !discoveryComplete {
        return nil, errors.New("cannot safely diff: filter-driver discovery failed")
    }
    args := []string{"-C", base}
    seen := map[string]struct{}{}
    for _, driver := range drivers {
        if !filterDriverName.MatchString(driver) {
            return nil, fmt.Errorf("cannot safely diff: unsupported Git filter driver name %q", driver)
        }
        // Os nomes das subseções do Git config diferenciam maiúsculas de minúsculas: não normalize os nomes dos drivers.
        key := driver
        if _, ok := seen[key]; ok {
            continue
        }
        seen[key] = struct{}{}
        for _, setting := range []string{"clean", "smudge", "process", "required"} {
            args = append(args, "-c", "filter."+driver+"."+setting+"=")
        }
    }
    return append(args, "diff", "--no-ext-diff", "--no-textconv", "--relative", "HEAD", "--", filepath.FromSlash(rel)), nil
}

Lista de Verificação de Segurança para Engenharia

Fontes