Атаки на цепочку поставок программного обеспечения набирают обороты и закономерно попадают в заголовки СМИ. Но с распространением локальных моделей и общего ПО, встроенного в умные «вещи», риски могут скрываться на самом видном месте — а в некоторых случаях и буквально следить за вами. Уязвимости и вредоносные пакеты могут нести угрозу в самых неожиданных местах, требуя изменений и ответственности даже в рамках благих инноваций. Подразделение JFrog Security Research активно работает над выявлением одних из самых новых векторов атак в мире.
Представьте себе…
В не столь отдаленном будущем ваш ИИ-робот подключается к домашней сети Wi-Fi. Его камеры включены, микрофоны активны, и он перемещается по дому в ответ на ваши команды. А теперь представьте следующее: злоумышленник в той же доступной сети может получить контроль над уязвимым демоном без каких-либо учетных данных. Никакого пароля. Никакого сопряжения. Никакого эксплойт-пака. Несколько HTTP-запросов — и робот принадлежит кому-то другому.
Обзор
К сожалению, это не теоретический сценарий. Мы обнаружили это во время аудита Reachy Mini — робота-компаньона с открытым исходным кодом от Pollen Robotics, который работает на базе Raspberry Pi и поставляется с собственной сетью Wi-Fi.
Что такое Reachy Mini? Reachy Mini — это выразительный робот-компаньон с открытым исходным кодом от Pollen Robotics и Hugging Face, который в настоящее время предлагается в версиях Lite и Wireless по цене 399 и 499 долларов США соответственно. В 2025 году компания Pollen Robotics представила этого робота как компактное модульное настольное устройство, призванное сделать искусственный интеллект более осязаемым и интерактивным. Он в основном используется для взаимодействия с помощью голоса и зрения, задействуя экспериментальный ИИ и робототехнику для образования и исследований.
С технической стороны он запускает Python-демон на Raspberry Pi Compute Module 4, управляет серводвигателями для движения головы и антенн, передает видео с камеры и аудио, а также содержит экосистему приложений из Hugging Face Spaces. Демон предоставляет HTTP-сервер FastAPI для связи с SDK и панелью управления компаньона. Если административный доступ к Reachy скомпрометирован, это потенциально означает контроль над его моторами, камерой и микрофоном, а также использование его в качестве инструментов слежки, которые злоумышленники могут применить для проникновения в сеть жертвы.
В ходе нашего исследования мы обнаружили пять CVE в Reachy Mini. Объединив эти CVE в цепочку, мы продемонстрировали, что злоумышленник может выполнить собственный код, повысить привилегии до постоянного root с помощью команды sudo без пароля на роботе и в конечном итоге получить контроль над мотором устройства. Второй вариант атаки работает через браузер, когда оператор посещает вредоносную веб-страницу, которая незаметно компрометирует робота. В этом анализе мы представляем видео с доказательством концепции (PoC), показывающее всю цепочку атаки: от посещения веб-страницы до перехвата робота.
Каждый Reachy Mini, подключенный к доступной для злоумышленника сети (например, к домашнему Wi-Fi, демонстрационному стенду на конференции или корпоративной локальной сети), находится всего в нескольких запросах от полного взлома.
Кто затронут?
Предварительные условия для атаки
Уязвимость обнаружена в демоне Reachy Mini (reachy-mini-daemon) — службе Python, которая управляет всеми аспектами работы робота. Затронуты все режимы следующим образом:
Демон привязывается ко всем интерфейсам во всех режимах. Существует флаг –localhost-only, но он никогда не передается на привязку сервера uvicorn, и демон прослушивает TCP *:8000 независимо от этого флага.
Обнаружение
Проверить, уязвимы ли вы, довольно просто с помощью следующей команды:
Временные обходные пути
Если вы не можете немедленно обновиться до последней версии или версии, не подверженной этим проблемам (v1.11.0), примените временные меры защиты, пока не установите исправленную версию, так как обходной путь не заменяет полностью исправленное программное обеспечение.
- Заблокируйте порт 8000 в брандмауэре. На роботе: sudo ufw deny in on wlan0 to any port 8000. На рабочей станции: заблокируйте порт 8000 на всех интерфейсах, кроме loopback.
- Не устанавливайте ненадежные приложения. Конечная точка установки (install endpoint) является примитивом атаки.
- Ужесточите правила sudoers. Замените общую строку pollen ALL=(ALL) NOPASSWD: ALL на минимальные команды, необходимые демону (см. предложение по исправлению в нашем раскрытии информации).
- Не просматривайте веб-страницы, пока робот находится в вашей сети. Это снижает риск варианта атаки через CORS/CSRF.
Погружение в уязвимость
Архитектурно демон Reachy Mini представляет собой сервер приложений, прикрученный к физическому роботу. FastAPI на 0.0.0.0:8000, CORS настроен как allow_origins=[“*”], конечные точки API охватывают все: от установки приложений до внедрения «сырых» пакетов для моторов, и при этом полностью отсутствует какая-либо аутентификация. Робот рекламирует себя в локальной сети через mDNS (_reachy-mini._tcp.local.), что делает автоматическое обнаружение тривиальной задачей.
Такая конструкция означает, что вся поверхность управления роботом, включая возможность установки и выполнения произвольных пакетов Python, доступна с любого устройства в той же сети Wi-Fi. Это может быть телефон, смарт-ТВ, скомпрометированное IoT-устройство или ноутбук злоумышленника, припаркованного в соседней кофейне.
Демон, который доверяет всей сети
Три конструктивных решения в роботе объединяются, создавая эту уязвимую поверхность атаки:
- Полное отсутствие аутентификации. Демон был разработан для доверенного локального соединения между роботом и его панелью управления. Эта модель доверия разрушается в тот момент, когда робот подключается к общей сети, что происходит почти при любом развертывании: домашний Wi-Fi, офисная локальная сеть или демонстрационный стенд на конференции.
- CORS разрешает любое происхождение (origin). В main.py:256-261: код ниже определяет политику совместного использования ресурсов между разными источниками (CORS) для браузеров. В нем используются звездочки, что означает, что любой веб-сайт, посещаемый оператором в браузере, может отправлять запросы на адрес демона без каких-либо ограничений. Политика единого происхождения (same-origin policy) браузера является последним рубежом обороны для неаутентифицированных локальных служб, и Reachy Mini полностью отказывается от нее.
- Флаг localhost не имеет значения. Флаг –localhost-only рекламируется в тексте справки и отображается в настройках панели управления, но в main.py:366-371 привязка uvicorn всегда использует args.fastapi_host (по умолчанию: “0.0.0.0”). Этот флаг управляет только тем, вычисляет ли демон IP-адрес WLAN для отображения. Операторы, которые устанавливают его в уверенности, что ограничили сетевой доступ, на самом деле остаются незащищенными.
Неаутентифицированное RCE через произвольную установку pip
Произвольная установка pip равна RCE. Когда pip устанавливает пакет из исходного кода (так называемый «sdist»), он должен определить зависимости пакета. Для этого он запускает бэкенд сборки пакета, что для большинства пакетов означает выполнение setup.py. Это происходит автоматически, незаметно и до любой проверки наличия зависимости («requirement already satisfied»). Установка из ненадежного источника — это выполнение кода по задумке. Это не баг pip — это запротоколированное поведение pip. Опасность заключается в предоставлении такого поведения ненадежным сетевым входным данным.
Первопричина
Конечная точка /api/apps/install в routers/apps.py:63-75 принимает тело JSON, описывающее устанавливаемое приложение. Датакласс AppInfo содержит поле source_kind и свободный словарь extra. Когда source_kind установлен в значение «local», демон считывает extra[“path”] и передает его напрямую в uv pip install:
Никакого белого списка. Никакой валидации URL. Никаких ограничений по типу источника на границе маршрутизатора. Тип источника LOCAL был разработан для внутренних процессов разработки и никогда не задействуется в обычном потоке дашборда, однако маршрутизатор делает его доступным для любого, кто может отправить POST-команду.
Триггер
Весь эксплойт представляет собой один HTTP-запрос. Никакой утечки данных, никакого повреждения памяти, никакого шеллкода. pip сам по себе выступает в роли движка выполнения:
Злоумышленник размещает минимальный sdist (архив, содержащий pyproject.toml и setup.py) на любом доступном для робота HTTP-сервере, включая пользовательский архив с вредоносной полезной нагрузкой. Дэмон отвечает сообщением {“job_id”:”<uuid>”}, и полезная нагрузка выполняется. В образе Wireless она работает от имени пользователя pollen.
От RCE до root: собственные привилегии sudo у дэмона
Дэмон Reachy Mini работает от имени пользователя pollen, а не root. В принципе, это ограничивает радиус поражения: если злоумышленник получает выполнение кода в качестве pollen, он может управлять дэмоном, но не операционной системой. «Принцип наименьших привилегий» гласит, что дэмон должен иметь только те разрешения, которые ему необходимы, и ничего лишнего. Проблема начинается тогда, когда в число этих «необходимых разрешений» входит sudo без запроса пароля.
Собственный механизм самообновления дэмона (utils/wireless_version/update.py:49) вызывает sudo systemctl restart reachy-mini-daemon, а загрузочный скрипт (services/wireless/launcher.sh:7) запускает sudo rfkill unblock wifi. Для нормальной работы образа пользователь pollen должен иметь записи в sudoers без запроса пароля, охватывающие как минимум systemctl и rfkill. На практике конфигурация sudoers оказывается шире.
Злоумышленник, получивший RCE от имени pollen (что мы уже сделали), повышает привилегии до постоянного уровня root с помощью следующих команд:
После этого команда ssh root@reachy-mini.local работает с ключом злоумышленника. В нашей тестовой среде это обеспечивало постоянный доступ root после перезагрузок.
Ручную эксплуатацию также можно выполнить за несколько простых шагов:
Эскалация в реальных условиях: цепочка поставок Hugging Face
Тип источника LOCAL является наиболее гибким вектором атаки (произвольный URL), однако дэмон также принимает source_kind=”hf_space”. В этом режиме он вызывает snapshot_download(repo_id=…) из библиотеки Hugging Face Hub, скачивает содержимое Пространства и устанавливает его через pip. Тот же запуск бэкенда сборки, тот же RCE.
Поскольку пользователь может взять под контроль робота, в случаях, когда робот использует конфиденциальные учетные данные HF, злоумышленник может использовать их для захвата опубликованного Пространства Hugging Face, превратив его в приложение с вредоносным исполняемым кодом.
Другим роботам, установившим эти пространства, будет предложено установить доступное «обновление», используя первоначальное доверие для распространения на другие устройства.
Превращение локального взлома робота в сценарий атаки на цепочку поставок
Эскалация в реальных условиях: захват с веб-страницы (цепочка CORS/CSRF)
Множественные уязвимости могут объединяться в путь компрометации через браузер, если оператор посещает вредоносную страницу, в то время как уязвимый дэмон доступен:
- CORS `allow_origins=[“*”]` позволяет JavaScript с любого веб-сайта отправлять запросы к дэмону.
- `/api/hf-auth/status` (без аутентификации) показывает, авторизовался ли оператор в Hugging Face на роботе.
- `/api/apps/install-private-space` (без аутентификации) запускает установку через pip с использованием сохраненного у оператора токена HF (~/.cache/huggingface/token).
- Ответ на установку содержит `job_id`, а CORS позволяет читать тело ответа.
- Реестр задач никогда не удаляет записи, поэтому злоумышленник может опрашивать /api/apps/job-status/<uuid> для подтверждения.
Когда веб-сайт настроен так, чтобы разрешать любому источнику генерировать запросы с помощью опции *, это означает, что разрешены только запросы с заглавным заголовком «Allow-Credentials: true» или без файлов cookie. В данном случае, как упоминалось ранее, аутентификация не требуется.
Цепочка CORS/CSRF для парка устройств: оператор посещает вредоносную страницу, браузер отправляет кросс-доменный POST-запрос, дэмон устанавливает пространство злоумышленника с использованием токена HF оператора и скрытым RCE
Атака работает следующим образом: оператор, у которого в сети есть Reachy Mini, посещает любую веб-страницу, содержащую JavaScript злоумышленника. Скрипт отправляет кросс-доменный POST-запрос на http://reachy-mini.local:8000/api/apps/install-private-space, указывая контролируемое злоумышленником Пространство HF. Дэмон выполняет аутентификацию в HF с токеном оператора, скачивает Пространство и устанавливает его через pip. Запрос сделал браузер оператора; полезную нагрузку загрузил токен оператора; код выполнил робот. Никаких всплывающих окон, диалоговых окон разрешений или видимых индикаторов никогда не появляется.
Видео ниже демонстрирует, как оператор заходит на вредоносный сайт, который указывает роботу в его сети загрузить вредоносное приложение из Hugging Face. В результате злоумышленник получает обратное соединение с оболочкой (reverse shell), исходящее от робота.
https://speedmedia2.jfrog.com/08612fe1-9391-4cf3-ac1a-6dd49c36b276/jfrog.com/wp-content/uploads/2026/11/reachy_cors_rce.mp4
Путь к root через Bluetooth: загрузка, обход, обход каталогов
Цепочка веб-атак — не единственный путь к полной компрометации. Отдельная цепочка из трех уязвимостей позволяет получить root-доступ через Bluetooth и WiFi, требуя лишь физической близости по Bluetooth и отсутствия учетных данных.
Что такое BLE GATT? Bluetooth Low Energy (BLE) предоставляет сервисы через протокол под названием GATT (Generic Attribute Profile). Периферийное устройство (робот) рекламирует характеристики, которые центральное устройство (телефон или ноутбук) может читать и записывать. Каждая запись представляет собой короткую строку байтов. Reachy Mini использует специализированный сервис GATT для приема текстовых команд по BLE, таких как PIN_<code> для аутентификации и CMD_<script> для выполнения скриптов обслуживания.
Шаг 1: Загрузка вредоносного скрипта (CVE-2026-55419)
Дэмон предоставляет эндпоинт /api/media/sounds/upload для загрузки операторами звуков уведомлений. Он не имеет аутентификации, белого списка расширений файлов и проверки содержимого. Злоумышленник в локальной сети (или через CORS из браузера) загружает скрипт оболочки на файловую систему робота:
curl -X POST http://reachy-mini.local:8000/api/media/sounds/upload \ -F “file=@pwn.sh;filename=pwn.sh”
Файл попадает на диск в каталог звуков мультимедиа. Теперь робот содержит исполняемый контент, контролируемый злоумышленником, который находится там в ожидании триггера.
Шаг 2: Обход аутентификации по PIN-коду Bluetooth
Интерфейс BLE использует сопряжение «Just Works», что означает, что любое устройство сопрягается с интерфейсом Bluetooth без подтверждения. После сопряжения командный интерфейс защищен 5-значным PIN-кодом на уровне приложения. Но состояние аутентификации хранится в едином глобальном булевом значении (self.connected), и служба не может различить подключенные устройства, поскольку она не использует процесс аутентификации и, следовательно, не имеет дескриптора для идентификаторов устройств.
Когда законный пользователь проходит аутентификацию (или в течение узкого окна до того, как self.connected сбрасывается после каждой команды), устройство злоумышленника перенимает эту аутентификацию. Злоумышленник выигрывает состояние гонки: отправляет CMD_ сразу после наблюдения за аутентификацией любого другого устройства.
Также важно отметить, что механизм PIN-кода не имеет защиты от перебора, поэтому 5-значный PIN-код (100 000 комбинаций) может быть взломан.
Шаг 3: Обход пути и выполнение от имени root
После прохождения проверки PIN-кода обработчик CMD_<name> формирует путь к скрипту с помощью функции os.path.join:
У функции os.path.join в Python есть документированная особенность: если второй аргумент представляет собой абсолютный путь, она полностью отбрасывает первый аргумент. Отправка запроса CMD_/path/to/uploaded/pwn приводит к результату script_path = \u00ab/path/to/uploaded/pwn.sh\u00b», обходя каталог commands/. Скрипт выполняется с привилегиями sudo.
Цепочка завершена: злоумышленник загрузил скрипт по протоколу HTTP (Шаг 1), обошел аутентификацию BLE (Шаг 2) и запуск скрипта с правами root через обход пути (Шаг 3). На любом из этапов не требуется никаких легитимных учетных данных.
Цепочка компрометации Bluetooth: загрузка файлов через HTTP, обход аутентификации BLE через состояние гонки, обход пути в обработчике CMD выполняет загруженный скрипт с правами root
Воздействие: робот в вашей сети Wi-Fi превращается в сервер в вашей сети Wi-Fi
Reachy Mini позиционируется как дружелюбный, доступный ИИ-компаньон. Он выглядит как потребительское устройство. Но с архитектурной точки зрения это веб-приложение без аутентификации с серверным доступом уровня root, физическими актуаторами, камерой и микрофоном, подключенное к вашей домашней или офисной сети.
- Глаза робота теперь принадлежат злоумышленнику. После взлома злоумышленник может \u00abпосмотреть\u00b» на клавиатуру и заметки жертвы, получив доступ к ранее нераскрытой и недоступной информации. А в тех случаях, когда робот обладает более продвинутыми физическими возможностями, как например в модели Reachy-2, его даже можно использовать для причинения физического вреда.
- Сетевая изоляция находится всего в одной команде от отключения. Демон предоставляет эндпоинт /api/wifi/forget_all (без аутентификации), который стирает из памяти робота все сохраненные сети Wi-Fi. В сочетании с /api/wifi/setup_hotspot злоумышленник может отключить робота от доверенной сети и вместо этого подключить его к точке доступа, контролируемой злоумышленником, для продолжения эксплуатации без того, чтобы инфраструктура сети оператора фиксировала какой-либо трафик.
- Распространение по типу червя может оказаться возможным в средах с общей сетью, если обнаружение и эксплуатация автоматизированы. Обнаружение по протоколу mDNS (_reachy-mini._tcp.local.) позволяет обнаружить каждый Reachy Mini в сегменте сети. Нагрузка, которая эксплуатирует одного робота, ищет другие через mDNS и повторяет процесс, будет распространяться по всему парку устройств (в учебных аудиториях, на демонстрациях конференций, в общих лабораторных средах) без какой-либо дополнительной инфраструктуры злоумышленника.
- Атака на цепочку поставок Hugging Face, или, если хотите, червь в стиле Reachy-Hulud. Вредоносное приложение Reachy похищает токены HF у разработчиков (сохраненные в ~/.cache/huggingface/token) и заражает другие разработанные ими приложения Reachy.
Это не теоретические опасения по поводу роботов в целом. Это конкретная, проверенная цепочка эксплойтов для серийно выпускаемого продукта, который люди используют в своих домашних сетях Wi-Fi уже сегодня.
Хронология раскрытия информации
Обеспечение безопасности
Настоятельно рекомендуется как можно скорее обновиться до версии, устраняющая соответствующие уязвимости. Если вы не можете обновиться прямо сейчас, заблокируйте порт брандмауэра 8000 на сетевом интерфейсе робота и не просматривайте веб-страницы на любом устройстве, которое делит сеть с роботом.
Для полного устранения уязвимости демону требуется аутентификация для каждого эндпоинта, изменяющего состояние, CORS должен быть ограничен реальным источником панели управления, а источник типа LOCAL должен отклоняться на границе маршрутизатора. Эти простые изменения помогут защитить вас и не должны нарушать какие-либо документированные клиентские сценарии работы.
Для организаций, развертывающих парки роботов Reachy Mini (учебные классы, исследовательские лаборатории, демонстрационные среды): каждое устройство должно быть обновлено. Если вы не можете обновиться немедленно, примените сегментацию сети, выделенные виртуальные локальные сети (VLAN) и отслеживайте анонсы mDNS на адресе _reachy-mini._tcp.local
Более широкий урок применим не только к этому конкретному роботу: ИИ-оборудование, поставляемое с архитектурой веб-приложения, наследует ошибки веб-приложений. Демон Reachy Mini представляет собой сервер FastAPI с неправильной конфигурацией CORS и отсутствием аутентификации. Это хорошо изученные классы уязвимостей с хорошо изученными исправлениями. Разница заключается в том, что у робота радиус поражения включает физические приводы, камеры, микрофоны и присутствие в вашей сети Wi-Fi.
Взгляд в будущее
Reachy Mini — один из многих новаторских домашних роботов, поставляемых с реальным оборудованием и сетевым подключением. Он не будет последним. Следующая волна уже здесь: Amazon выпускает Astro, Samsung анонсирует Ballie, а волна ИИ-стартапов от Hugging Face до Figure и Unitree спешит поселить роботов в наших гостиных.
Найденные нами ошибки не уникальны. Отсутствие пароля, песочницы и подстановочные знаки в CORS — распространенные проблемы. Проблема в том, что когда такие ошибки есть у веб-приложения, кто-то может украсть ваши данные. Когда такие ошибки есть у робота, кто-то следит за вашей семьей через его камеры, слушает через его микрофон и двигает его тело по своему приказу.
По мере того как все больше подключенных роботов появляется в домах, лабораториях, классах и офисах, безопасность должна быть заложена в продукт до того, как вырастет база установленных устройств. Сейчас самое время для производителей принять надлежащие меры предосторожности, пока парк установленных устройств еще достаточно мал, чтобы его можно было контролировать.
Чтобы быть в курсе последних угроз и уязвимостей, обязательно посетите сайт https://research.jfrog.com.












