3 августа 2026 года один из наших клиентов Metabase Cloud сообщил, что вне рабочего времени был создан ключ API.
Мы провели расследование и заметили аномальный шаблон доступа: с одного IP-адреса был создан ключ API на двух разных экземплярах клиентов в одинаковой последовательности конечных точек. Мы определили исходную конечную точку, с которой началась цепочка атак, и установили сетевую блокировку для всех наших экземпляров клиентов.
Мы провели расследование и выяснили, что создавался действительный идентификатор сеанса, и с помощью обратной разработки обнаружили неизвестную уязвимость («нулевого дня»), которая позволяла злоумышленнику генерировать активный сеанс. Мы создали патч и немедленно развернули его на наших клиентских облачных экземплярах.
Мы выполнили поиск по логам и начали расследование возможных последствий для клиентов. Мы также привлекли стороннюю компанию по реагированию на инциденты и проведению криминалистической экспертизы.
Мы начали подготовку публичного релиза и в ходе расследования обнаружили еще несколько производных уязвимостей, проистекающих из того же примитива, и добавили исправления для этих уязвимостей в релиз.
Мы упаковали эти исправления и выпустили исправленные версии 6 августа.
Кто пострадал?
Все установки Metabase, использующие версии 0.58 и более поздние, были уязвимы.
Менее 3% наших облачных клиентов были скомпрометированы в результате уязвимости до применения патча, как и некоторые пользователи с открытым исходным кодом и клиенты с самостоятельным размещением, имеющие общедоступные экземпляры Metabase.
В чем заключалась неизвестная уязвимость?
Уязвимость представляла собой цепочку атак, в которой использовалось взаимодействие четырех уровней нашей кодовой базы.
Отправной точкой атаки стал наш URL-адрес сброса пароля (/reset-password).
Этот URL-адрес принимал тело запроса:
Первым звеном в этой цепочке был тот факт, что аннотации типов нашего API в Malli не были «закрытыми»; аннотации типов проверяли только то, что необходимые ключи присутствуют и имеют правильный тип. Дополнительные ключи не вызывали ошибку валидации.
Вторым шагом было то, что рефакторинг системы аутентификации от 11 ноября 2025 года изменил обработку параметров: вместо передачи только ключей токена и пароля стало происходить передача всего тела целиком.
Третьим шагом является то, что при входе в процесс аутентификации, если указан идентификатор пользователя, запись этого пользователя ищется по ID нашей ORM, Toucan2. Это выполнялось с помощью функции select-one в Toucan2, где в качестве «ID» пользователя выступало значение, переданное из URL-адреса сброса пароля.
Наконец, toucan2 использовал HoneySql для генерации запроса.
Если предикат фильтрации включал ключ «raw», honeysql обрабатывал его как «сырой» (raw) SQL, который нужно вставить без изменений.
Путем отправки тела запроса вида
злоумышленник мог внедрить SQL-код.
Сама атака использовала это для вставки записи в нашу таблицу сеансов с известным user_id, равным 1 (первый пользователь в экземпляре Metabase, всегда изначально создаваемый как «администратор»), а затем использовала этот сеанс для поиска данных и создания ключа API, позволяющего массово скачивать таблицы.
Какова была сигнатура этой атаки?
Хотя эту атаку можно выполнить различными способами, шаблон, который мы увидели, был следующим:
Что мы исправили?
Мы защитились от этой атаки на трех разных уровнях с помощью следующих мер:
- Передавать из обработчика API только поля токена и пароля
Передавать из обработчика API только поля токена и пароля
- Отклонять ключи, допускающие злоупотребления, при входе в процесс аутентификации
Отклонять ключи, допускающие злоупотребления, при входе в процесс аутентификации
- Вызывать исключения при обнаружении непредвиденных ключей в служебных макросах
Вызывать исключения при обнаружении непредвиденных ключей в служебных макросах
Что мы делаем для предотвращения подобного в будущем?
Из-за сложности этой атаки, необходимых знаний нашей кодовой базы и поведения двух вложенных зависимостей (Toucan2 и Honey SQL) мы считаем, что для этой атаки потребовались значительные возможности LLM.
В ранних запросах использовались строки user-agent, намекающие на обход защитных механизмов LLM: «metabase-postgres-admin-session-lab-verifier/1», «metabase-read-only-sqli-verifier/1», после чего происходило чередование 25 вариантов, похожих на «Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0» «Safari/537.36 Edg/146.0.0.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0».
Учитывая крайне быстрое увеличение возможностей сканирования кода с помощью LLM и их способности выстраивать глубокие цепочки атак, мы укрепляем защиту Metabase на всех уровнях, а не ограничиваемся исправлением только этой одной уязвимости.
Это укрепление происходит на многих уровнях нашей кодовой базы, включая:
- Предотвращение создания сеансов и других конфиденциальных значений в БД путем SQL-инъекций без внеполосного ключа шифрования;
- Включение закрытой по умолчанию валидации схем на всех конечных точках;
- Добавление дополнительной валидации данных;
- Унификацию разрозненных проверок разрешений;
- Предотвращение SQL-инъекций в Toucan через параметр raw в HoneySQL;
- Укрепление нашего процессора запросов MBQL для запрета вывода «сырого» SQL без кавычек;
- Блокировку потенциальных векторов SSRF;
- Увеличение разделения кэш-ключей между пользователями;
- Укрепление песочницы (Sandbox) и олицетворения подключений к БД (DB ConnectionImpersonation); и
- многое другое.
Мы выпустили первую партию этих мер по усилению безопасности в версии 63.13 и выпустим еще один релиз с улучшениями безопасности перед возвращением к нашему обычному циклу разработки.
Мы также сотрудничаем с внешними исследователями (еще одно спасибо Ophion Security и ред-тим Anthropic) и продолжаем сканировать нашу кодовую базу с помощью еще большего разнообразия моделей и подходов.







