flawopen.com/Teardowns/cve-2026-102437-deepseek-reasonix-git-filter-command-injection
CVE-2026-102437: внедрение команд Git в Reasonix
Связка .gitattributes/.git/config может запустить фильтр clean при просмотре diff в Reasonix. Обновите npm до 1.39.3 или Studio до 2.21.0.[1], [2], [3], [6], [7]
Представьте сортировочный стол, который должен только сравнивать две этикетки. На посылке может быть маршрутная записка с указанием запустить зарегистрированный помощник перед сравнением содержимого. Reasonix отключал некоторые механизмы Git, но фильтр clean для отдельных файлов был отдельным путём. Когда окно diff просило Git подготовить файл к сравнению, фильтр мог выполниться с правами разработчика.[1], [3]
Ключевые понятия и термины
Фильтр Git clean- Настроенное преобразование, которое Git может выполнить, чтобы привести файл из рабочего дерева к виду, хранящемуся в репозитории.[1], [3]
.gitattributes- Отслеживаемый в репозитории файл, назначающий именованный фильтр выбранным путям.[1]
.git/config- Локальная конфигурация репозитория, в которой задаётся команда именованного фильтра. Обычное клонирование не копирует этот локальный файл.[1], [3]
Окно diff- Функция, которая просит Git подготовить и сравнить рабочее содержимое файла с зафиксированным в репозитории.[1]
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-78
Анализ первопричины
Reasonix усиливал вызовы git diff параметрами --no-ext-diff и --no-textconv , но они управляют внешним diff и преобразованием текста, а не отключают контентные фильтры clean в Git. Окно изменений рабочего пространства вызывало git diff для выбранного пути. Если содержимое репозитория назначало этому пути фильтр через .gitattributes , а локальная конфигурация Git задавала команду драйвера, Git мог запустить её при подготовке сравниваемого blob. CVE описывает локального атакующего и требует, чтобы пользователь открыл diff. В публикации GitLab сказано, что обычное клонирование не переносит .git/config ; этот файл могут содержать архивы, синхронизированные каталоги, кэши или заранее собранные devcontainer-образы. Там же описан вариант, когда локальный агент с теми же правами записывает конфигурацию в репозиторий. Последствие — выполнение команд с правами пользователя Reasonix, а не удалённое выполнение кода при простом открытии репозитория на GitLab.[1], [3]
Пошаговый сценарий атаки
Рабочая область получает недоверенное состояние репозитория
Разработчик открывает проект, где отслеживаемые атрибуты назначают файлу фильтр, а локальная конфигурация Git определяет этот фильтр. В уведомлении сопровождающего требуются оба элемента; одного обычного клонирования недостаточно для получения локальной конфигурации.[1], [3]
Исходный код: Уязвимый vs Защищённый вариант
Этот построитель аргументов дан для иллюстрации и не является готовым патчем. Вызывающая сторона должна перечислить все драйверы, выбранные .gitattributes, .git/info/attributes и глобальными/системными файлами атрибутов, и задавать discoveryComplete только после успешного полного поиска. Эта функция проверяет переданные имена и формирует переопределения конфигурации в командной строке; она не обнаруживает и не проверяет набор драйверов. Уязвимый вызов приведён в раскрытии GitLab; защитный подход представляет собой собственный синтез рекомендаций сопровождающих и их принятых PR по усилению защиты.[1], [3], [4], [5]
Фрагмент исходного кода: desktop/workspace_changes.go
// Исходный вызов, приведенный GitLab Threat Research; это место вызова, а не полная функция.
args := []string{"-C", base, "diff", "--no-ext-diff", "--no-textconv", "--relative", "HEAD", "--", filepath.FromSlash(rel)}
// Иллюстративный конструктор аргументов Go, а не дословный патч поставщика.
package gitguard
import (
"errors"
"fmt"
"path/filepath"
"regexp"
)
// Вызывающая сторона должна найти все фильтры, выбранные действующими атрибутами, и передать полный набор.
// Этот вспомогательный код лишь отключает эти ключи driver во всех областях конфигурации 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)
}
// Имена подразделов Git config чувствительны к регистру: не приводите имена 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
}
Чек-лист по защите системы для инженеров
- ✓✓ Обновите пакет Reasonix npm до версии 1.39.3 или новее либо Reasonix Studio до 2.21.0 или новее согласно актуальным рекомендациям проекта.[2], [6], [7]
- ✓✓ Если инструмент запускает Git в рабочей области, контролируемой пользователем, считайте локальную конфигурацию и отслеживаемые атрибуты репозитория недоверенными.[1], [3]
- ✓✓ При каждом вызове Git от имени хоста, преобразующем содержимое, определяйте фильтры, выбранные
.gitattributes,.git/info/attributesи глобальными или системными файлами атрибутов; нейтрализуйте ключи драйверов в областях system, global, local и worktree и безопасно прерывайте операцию при неполном обнаружении.[1], [3], [4], [5] - ✓✓ Используйте
--no-ext-diffи--no-textconvкак отдельные меры защиты; они не заменяют нейтрализацию драйверов фильтров.[1] - ✓✓ Добавьте регрессионные тесты с настоящим Git, подтверждающие, что заданный в репозитории недоверенный фильтр не запускается через diff, status, staging, checkout и другие поддерживаемые wrapper операции с содержимым.[4], [5]
- ✓✓ Проверьте архивы, общие папки, кэши и devcontainer на локально добавленный
.git/config; не утверждайте, что обычный clone переносит этот файл.[1], [3]
Источники
- GitLab Threat Research — DeepSeek-Reasonix vulnerability details and affected call site
- GitLab Advisory Database — CVE-2026-102437
- DeepSeek-Reasonix maintainer advisory — GHSA-grg2-7gc6-36m6
- DeepSeek-Reasonix Studio host Git hardening PR #11110
- DeepSeek-Reasonix 1.x host Git hardening PR #11114
- DeepSeek-Reasonix 1.39.3 release
- DeepSeek-Reasonix Studio 2.21.0 release
- MITRE CWE-78 — Improper Neutralization of Special Elements used in an OS Command