FlawOpen

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

● CVE-2026-102437 · CVSS 7.8[2] · Alta
Investigación · FlawOpen

CVE-2026-102437: inyección Git al ver diffs en Reasonix

Un par .gitattributes/.git/config manipulado puede ejecutar un filtro clean al ver un diff en Reasonix. Actualiza npm a 1.39.3 o Studio a 2.21.0.[1], [2], [3], [6], [7]

💡 Explicación en Lenguaje Sencillo (ELI5)

Imagina una mesa de clasificación que promete comparar solo dos etiquetas. Un paquete puede incluir una nota de ruta que ordena a la mesa ejecutar un auxiliar registrado antes de comparar el contenido. Reasonix desactivaba algunos auxiliares de Git, pero el filtro clean por archivo era una vía distinta. Cuando la pantalla de diferencias pidió a Git preparar el archivo, ese filtro podía ejecutarse con los permisos del desarrollador.[1], [3]

Conceptos Clave y Términos

Filtro clean de Git
Transformación configurada que Git puede ejecutar para convertir el contenido de un archivo del árbol de trabajo al formato almacenado en el repositorio.[1], [3]
.gitattributes
Archivo versionado del repositorio que puede asignar un filtro con nombre a determinadas rutas.[1]
.git/config
Configuración local del repositorio que puede definir qué comando ejecuta un filtro. Un clon normal no copia este archivo local.[1], [3]
Visor de diferencias
Función que pide a Git preparar y comparar el contenido actual de un archivo con el contenido confirmado.[1]

Mapeos de marcos

  • Referencia CWE para la debilidad descrita en esta guía: CWE-78

Análisis de Causa Raíz

Reasonix reforzaba las llamadas a git diff con --no-ext-diff y --no-textconv , pero esas opciones controlan mecanismos de diferencias externas y conversión de texto; no desactivan los filtros clean de contenido de Git. La vista de cambios del espacio de trabajo llamaba a git diff para una ruta seleccionada. Si el contenido del repositorio asignaba un filtro mediante .gitattributes y la configuración local de Git definía el comando de ese controlador, Git podía ejecutarlo al construir el objeto de comparación. El CVE describe un atacante local y requiere que el usuario abra la diferencia. La divulgación de GitLab indica que un clon normal no transfiere .git/config ; archivos comprimidos, carpetas sincronizadas, cachés o devcontainers preparados sí pueden incluirlo. También describe la posibilidad de que un agente local con los mismos permisos escriba configuración local en el repositorio. El impacto es la ejecución de comandos con los permisos del usuario de Reasonix, no la ejecución remota por el mero hecho de abrir un repositorio alojado en GitLab.[1], [3]

Flujo de Ataque Paso a Paso

Paso 1

El espacio de trabajo recibe estado de repositorio no confiable

El desarrollador abre un proyecto cuyos atributos versionados asignan un archivo a un filtro y cuya configuración Git local define ese filtro. El aviso del mantenedor requiere ambos elementos; un clon normal por sí solo no aporta la configuración local.[1], [3]

Paso 2

El desarrollador solicita una diferencia

La vista de cambios de Reasonix ejecuta el flujo de diferencias de Git para el archivo seleccionado. Esta acción de interfaz es la interacción que exige el CVE.[1], [3]

Paso 3

Git aplica el filtro clean

Git prepara el contenido para compararlo y puede invocar el filtro clean configurado. --no-ext-diff y --no-textconv desactivan mecanismos distintos y no suprimen este filtro.[1], [3]

Paso 4

El filtro se ejecuta con los permisos del usuario

El comando configurado para el filtro se ejecuta en el contexto del proceso de Reasonix. La consecuencia documentada es la ejecución local de comandos con los permisos de ese usuario.[1], [2], [3]

Código Fuente: Vulnerable vs. Seguro

Este constructor de argumentos es ilustrativo, no un parche listo para usar. El llamador debe enumerar todos los drivers seleccionados por .gitattributes, .git/info/attributes y los archivos de atributos globales/del sistema, y establecer discoveryComplete solo después de completar correctamente el análisis. Esta función valida los nombres recibidos y genera anulaciones de configuración en la línea de comandos; no descubre ni verifica el conjunto de drivers. La llamada vulnerable está citada en la divulgación de GitLab; el patrón defensivo es una síntesis original de la guía de los mantenedores y de sus PR de hardening fusionados.[1], [3], [4], [5]

Fragmento de origen: desktop/workspace_changes.go

IMPLEMENTACIÓN VULNERABLE
// Llamada de origen citada por GitLab Threat Research; es el punto de llamada, no una función completa.
args := []string{"-C", base, "diff", "--no-ext-diff", "--no-textconv", "--relative", "HEAD", "--", filepath.FromSlash(rel)}
PARCHE SEGURO Y ROBUSTO
// Constructor ilustrativo de argumentos Go, no un parche literal del proveedor.
package gitguard

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

// El llamador debe descubrir todos los filtros seleccionados por los atributos efectivos y pasar el conjunto completo.
// Este auxiliar solo neutraliza esas claves de driver en todos los ámbitos de configuración de 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)
        }
        // Los nombres de subsección de Git config distinguen mayúsculas: no normalice los nombres de driver.
        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 Verificación de Seguridad para Ingeniería

Fuentes