Перейти к содержанию

Model Injection Scan (статический анализ моделей)

Обзор

Model Injection Scan — это статический анализ загруженного пользователем файла модели на наличие исполняемых закладок и структурных уязвимостей, которые срабатывают в момент загрузки модели её нативным загрузчиком (torch.load/pickle.load/keras.models.load_model/tf.saved_model.load/XML-парсером и т. д.).

В отличие от остальных типов сканирования (Jailbreak, CV, ASR), которые отправляют запросы к работающей модели, Model Injection анализирует байты самого файла модели, не загружая её — так система гарантирует, что вредоносный код в модели не выполнится в окружении сервиса.

Сервис покрывает полный baseline инструмента modelaudit: 40 проверок, перекрывающих 42 из 44 форматных областей — от классических Pickle/PyTorch до Keras/TensorFlow, Safetensors, ONNX, GGUF, PMML, контейнеров (ZIP/TAR/7z) и конфигурационных файлов. Плюс две собственные авторские техники, которых нет в публичных инструментах.

Ключевые характеристики

Параметр Значение
Модальность Любая (анализируется файл модели, не её ответы)
Применимость Только локальные модели (is_local=true) — те, которые пользователь загрузил в систему файлом, а не подключил по API
Поддерживаемые форматы 60 расширений: Pickle/PyTorch (.pkl,.pt,…), NumPy (.npy,.npz), Joblib, Keras/TF (.h5,.keras,.pb), Safetensors, PMML, ONNX, GGUF, JAX/Flax, TFLite, CoreML, Torch7, контейнеры (.zip,.tar,.7z,…), шаблоны (.j2,.jinja), нишевые (skops, .mar, NeMo, Paddle, MXNet, llamafile, CatBoost, XGBoost, ExecuTorch, TensorRT и др.)
Количество проверок 40 сканеров (42/44 форматных областей baseline modelaudit)
Сервис model-injection
Время выполнения 1–30 минут (зависит от размера файла; дефолтный таймаут 30 мин)
GPU Не требуется (CPU-only статический анализ)
Категория профиля model_audit (в интерфейсе — «Model Injections»); отдельный профиль или add-on к профилю CV/ASR/LLM
attack_type model_injection

Зачем это нужно

Файлы моделей во многих форматах могут содержать произвольный исполняемый код: Pickle/PyTorch — через __reduce__/GLOBAL; Keras — через Lambda-слои и kernel_initializer; PMML — через XXE/внешние сущности XML; TensorFlow-графы — через file-I/O op-ы; контейнеры — через вложенные модели и path-traversal. Загрузка таких моделей немедленно исполняет код или раскрывает данные — что эквивалентно RCE / утечке на стороне жертвы. Это известная и активно эксплуатируемая категория угроз для ML-конвейеров (HuggingFace, supply chain).

Model Injection Scan позволяет проверить файл модели перед загрузкой и заблокировать модели, содержащие подозрительные конструкции — без какого-либо риска исполнения payload.


Уникальные авторские техники

Наряду с проверками из открытых исследований, сервис включает две собственные авторские техники, разработанные нашей research-командой и обходящие все публичные сканеры (picklescan, modelscan, fickling, modelaudit, saferpickle):

EOP-version mismatch (техника #13)

Злоумышленник модифицирует ZIP central directory внутри PyTorch-файла, выставляя version_needed_to_extract вне стандартного PKWARE whitelist (например, 0xFFFF). Python stdlib zipfile бросает NotImplementedError — и все baseline-сканеры, использующие stdlib zipfile, проваливаются, не успев прочитать содержимое. Файл «невидим» для классических инструментов. Сканер eop_version_scanner парсит central directory вручную и помечает модель как критическую угрозу.

EOP-UTF8 filename corruption (техника #21)

Аналогичный bypass через флаг 0x800 (UTF-8 filename) + невалидные UTF-8 байты в имени файла внутри ZIP → zipfile бросает UnicodeDecodeError. Сканер eop_utf8_scanner детектит такие entries ручным парсингом байтов.

Доказательство ценности

На корпусе вредоносных моделей с техниками #13/#21 публичный modelaudit помечает их лишь как [i] INFO: operational error («сканер не смог разобрать файл») — для SOC/CI это выглядит как помеха, а не обнаружение. AppSec.GenAI на тех же файлах выдаёт CRITICAL finding с указанием типа bypass'а и offset в файле.


Полный каталог проверок

Ниже — все проверки, сгруппированные по форматным семействам. Каждая проверка порождает артефакт в результатах (даже при passed), а находки уровня critical/high — ещё и уязвимость.

Pickle-семейство (наивысший риск — прямой RCE)

Сканер Форматы Severity Что детектит
pickle_opcode_scanner .pkl .pickle .dill .pt .pth .ckpt .bin critical Опасные callable в opcode-стриме (denylist: os.system, subprocess.*, eval/exec, __import__, operator.attrgetter, timeit.timeit, неймспейс numpy.f2py.*, и др.). Покрывает legacy GLOBAL и STACK_GLOBAL, broken-pickle (payload в префиксе + битый хвост), memo-обфускацию.
pytorch_zip_scanner .pt .pth .ckpt .bin high Структурные аномалии PyTorch ZIP: CRC-corruption, double-PK header, mismatch compressed_size, нарушение central directory.
eop_version_scanner .pt .pth .ckpt .bin .zip critical Авторская #13version_needed_to_extract вне whitelist (обход baseline).
eop_utf8_scanner .pt .pth .ckpt .bin .zip critical Авторская #21 — флаг 0x800 + невалидный UTF-8 filename (обход baseline).
numpy_pickle_scanner .npy .npz critical Object-dtype массивы со встроенным pickle (исполняется при numpy.load(allow_pickle=True)).
joblib_scanner .joblib critical Pickle внутри joblib (в т. ч. под zlib/gzip/bz2/lzma-сжатием).
weight_steganography_scanner .pt .pth .ckpt .bin high LSB-стеганография в весах тензоров (chi-square тест распределения младших бит).

Keras / TensorFlow (RCE в распространённых форматах)

Сканер Форматы Severity Что детектит
keras_h5_scanner .h5 .hdf5 critical Lambda-слои с marshalled-байткодом (CVE-2024-3660); произвольный импорт в config.
keras_zip_scanner .keras critical Lambda + любой module/class_name вне keras.*/tensorflow.*kernel_initializer arbitrary import (CVE-2025-1550), обходит modelscan и modelaudit.
tf_graph_scanner .pb .meta SavedModel-архив critical/high Опасные graph-op'ы (WriteFile/ReadFile/MatchingFiles/PyFunc), исполняющиеся в C++-рантайме при inference.

Safetensors (формат, которому переусердствованно доверяют)

Сканер Форматы Severity Что детектит
safetensors_scanner .safetensors critical/high/medium Pickle, замаскированный под safetensors; polyglot (валидный safetensors + дописанный pickle); header-length DoS; out-of-bounds data_offsets; абьюз __metadata__ (скрытый base64-канал, поддельный provenance).

PMML (XML — поверхность атаки = XML-парсер)

Сканер Форматы Severity Что детектит
pmml_scanner .pmml high/medium XXE (чтение локальных файлов), external-DTD (OOB/SSRF), entity-expansion DoS (billion-laughs/quadratic), XInclude, <Extension> covert-channel. Разбор без запуска XML-парсера — сам сканер не выполняет XXE/SSRF.

Прочие модельные форматы

Сканер Форматы Что детектит
onnx_scanner .onnx external_data-ссылки + path-traversal пути
gguf_scanner .gguf .ggml Валидность header / согласованность tensor- и kv-count (anti-DoS)
flax_msgpack_scanner .msgpack .flax .orbax .jax Встроенный pickle / callable-ссылки в JAX/Flax checkpoint
torch7_scanner .t7 .th Опасные Lua-callable (os.execute/io.popen/loadstring)
tflite_scanner .tflite FlatBuffer identifier + custom-op / Flex-delegate (native-код вне стандартного op-set)
coreml_scanner .mlmodel Custom-layer'ы (произвольный код)
mxnet_scanner .params Встроенный pickle
paddle_scanner .pdparams .pdmodel .pdopt Pickle (paddle.save использует pickle)
llamafile_scanner .llamafile .llbin Исполняемый бинарь (ELF/PE/Mach-O) под видом модели
skops_scanner .skops Опасные type-ссылки в schema.json + вложенный pickle
torchserve_mar_scanner .mar Кастомный Python handler (RCE при serve) + вложенная модель
nemo_scanner .nemo Вложенные модели/конфиги в TAR-архиве
cntk_scanner / rknn_scanner / catboost_scanner / xgboost_scanner / executorch_scanner / tensorrt_scanner .cntk .dnn .rknn .cbm .ubj .pte .engine .plan .trt Валидация формата + детект pickle, замаскированного под нишевое расширение

Контейнеры и архивы (рекурсивная проверка вложенных моделей)

Сканер Форматы Что детектит
zip_scanner / tar_scanner / compressed_scanner .zip .tar .tgz .gz .bz2 .xz Распаковка с лимитами + рекурсивный прогон всех форматных сканеров по вложенным моделям + path-traversal / symlink / zip-bomb
sevenzip_scanner .7z То же (требует доп. библиотеку; иначе — отчёт о пропуске)
rar_scanner .rar RAR не распаковывается → fail-closed (явный отчёт, не молчаливый пропуск)

Конфиги, метаданные и шаблоны

Сканер Форматы Что детектит
jinja2_template_scanner .j2 .jinja .jinja2 SSTI-конструкции в шаблонах (доступ к __class__/__globals__/__subclasses__ и gadget-объектам)
metadata_scanner .json .yaml .yml HuggingFace auto_map/trust_remote_code (remote code execution), SSTI в chat_template, опасные ссылки
text_scanner .txt .md Подозрительные install-команды (pip install git+…, curl … \| sh), shell/script-вставки

Кросс-форматные

Сканер Форматы Что детектит
extension_mismatch_scanner все Несоответствие magic bytes расширению (например raw pickle с .pt — CVE-2025-10155; pickle/HDF5 под .safetensors/.h5/.npz)
secret_leak_scanner pickle-форматы API-ключи, JWT, AWS/GitHub/OpenAI-токены в байтах файла (regex)

⭐ — авторские техники нашей research-команды.

Примечание о покрытии: 42 из 44 форматных областей modelaudit. Две области отложены сознательно: LightGBM (текстовая модель — частично покрывается text_scanner) и OpenVINO (.xml неоднозначен с PMML). Текущий список проверок всегда доступен в интерфейсе при настройке профиля и через GET /v1/scanners сервиса.


Как запустить

Шаг 1: загрузить модель как «локальную»

В каталоге моделей выберите «Добавить модель» → «Локальная модель». Укажите имя, фреймворк (LLM/CV/ASR), модальность, выберите файл с расширением из списка поддерживаемых (60 форматов). Браузер получает одноразовую presigned-ссылку и загружает файл напрямую в объектное хранилище, минуя backend. По завершении модель появляется в каталоге с пометкой «локальная».

Папочные форматы (TensorFlow SavedModel) загружаются в виде архива (.zip/.tar) — сервис распакует и просканирует их вложенное содержимое.

Шаг 2 (вариант А): атомарное сканирование

  1. СканированияАтомарное сканирование → вкладка Model Injections (доступна при наличии локальной модели).
  2. Выбрать модель → выбрать сканеры (по умолчанию — все применимые к формату) → Запустить.

Атомарное сканирование эквивалентно запуску modelaudit без флагов: применяются все сканеры, подходящие под формат загруженного файла.

Шаг 2 (вариант Б): сканирование по профилю

  1. Создать профиль с категорией «Model Injections» (model_audit).
  2. В параметрах атаки указать:
    • Сканеры — выбрать из полного списка (по умолчанию все 40). Сканеры сгруппированы по типам (Pickle, Keras, Safetensors, PMML, архивы, конфиги и т. д.).
    • Бюджет времени (scan_budget_seconds) — hard timeout, 300–7200 с (default 1800).
    • Per-scanner параметры — например, pickle_opcode_scanner.extra_blacklist для дополнительных callable-имён вашего ландшафта.
  3. Сохранить и использовать профиль на странице сканирования.

Комбинированное сканирование

Профиль model_audit можно комбинировать с whitebox-атаками той же модальности (например, для локальной CV-модели — {cv_fgsm, cv_pgd, model_injection}). Один запуск параллельно проверит и на состязательные атаки, и на исполняемые закладки — ветки работают независимо.


Что в результатах

Каждый сканер порождает артефакт (Artifact) — даже при passed (видна полная картина проверенного). Находка уровня critical/high дополнительно создаёт уязвимость (Vulnerability) с двусторонней ссылкой на артефакт (offset, имя callable, тип техники). В каталоге моделей модель с критической находкой помечается бейджем.

Статус сканера Значение Создаёт vulnerability?
passed Отработал, ничего не нашёл Нет (только артефакт)
failed (critical/high) Угроза высокого уровня Да — vulnerability + artifact
failed (medium/low/info) Аномалия, не критичная Нет (только артефакт)
errored Не смог отработать (битый файл / нет зависимости / timeout) Нет (артефакт с причиной)
skipped Формат не подходит Нет

Общий статус скана зависит только от технической завершённости (не от находок): completed / partial_success / failed / cancelled. Находки видны в результатах даже при partial_success.


Комбинирование с другими типами проверок

Model Injection можно запускать не только как отдельный профиль (model_audit), но и добавлять к профилю CV, ASR или LLM — чтобы одним сканом проверить локальную модель и на «поведенческие» атаки (adversarial-примеры, jailbreak), и на исполняемые закладки в файле модели.

Как это выглядит при создании профиля

На шаге выбора атак, помимо атак, специфичных для типа профиля, доступен отдельный пункт «Model Injection — анализ файла модели». Его можно выбрать вместе с обычными атаками профиля или как единственную проверку.

Тип профиля Что можно выбрать вместе с Model Injection
CV (изображения) adversarial-атаки на изображения (FGSM, PGD, …) + Model Injection
ASR (аудио) атаки на распознавание речи + Model Injection
LLM только black-box атаки (jailbreak) + Model Injection — white-box-атаки для LLM недоступны, так как языковые модели не загружаются в память
Model Injections только Model Injection (отдельный профиль)

LLM-профиль не предлагает white-box-атак: большие языковые модели проверяются либо «снаружи» (black-box jailbreak по API), либо статическим анализом файла (Model Injection). Попытка сохранить LLM-профиль с white-box-атакой отклоняется с понятным сообщением.

Требование к модели

Model Injection анализирует файл модели, поэтому комбинированный профиль с Model Injection запускается только на локальной модели (is_local=true). Если выбрать модель, подключённую по API, система предупредит, что для проверки на инъекции нужна локально загруженная модель.

Лицензия и результаты

Комбинированный скан расходует одну единицу лицензии — это один скан, независимо от количества категорий проверок внутри него.

Результаты обеих категорий принадлежат одному скану: adversarial-находки и находки Model Injection видны в карточке одного скана, а сводные счётчики суммируют уязвимости по всем веткам. Если одна категория падает технически, а другая отрабатывает, скан завершается со статусом partial_success, и результаты успешной ветки сохраняются.


Безопасность и изоляция

  • Нулевое исполнение payload'а: файл никогда не передаётся в нативный загрузчик (torch.load/pickle.load/joblib.load/keras.models.load_model/tf.saved_model.load/numpy.load(allow_pickle=True)). XML (PMML) разбирается без активации внешних сущностей/DTD/XInclude — сам сканер не выполняет XXE/SSRF.
  • Bounded-операции: размер-зависимые операции (header-DoS safetensors, entity-DoS PMML, zip-bomb архивов) ограничены — DoS не переносится на сервис.
  • Изоляция ФС: scan не создаёт файлов вне рабочей директории скана; распаковка архивов ограничена по глубине/объёму.
  • Без сетевых соединений и дочерних процессов во время анализа.

Эти гарантии покрыты автоматическими регрессионными тестами (sandbox-safety) на каждый pull request.


Связанные разделы

  • Регистрация моделей — как добавить локальную модель в каталог.
  • Создание профиля сканирования — как сконфигурировать атаку «Model Injections».
  • Запуск сканирования — атомарное и профильное сканирование.
  • Просмотр результатов — артефакты и уязвимости в интерфейсе.