
SQL-инъекция в оптимизаторе агрегации MongoLite через toJsonExtractRaw()
cockpithq/cockpit:core-2.13.47fe563023b7fae854c857d2e2dc0878ef28fbb5f (тег 2.13.4)CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:NУязвимость SQL-инъекции обнаружена в Cockpit CMS (Core Edition версии 2.13.4). Уязвимость находится в оптимизаторе агрегации MongoLite, а именно в методе . Управляемые пользователем имена полей конкатенируются непосредственно в SQL-запросы без надлежащей санитизации.
toJsonExtractRaw()Аутентифицированный злоумышленник с доступом на чтение (через API-ключ) к модели контента может внедрить произвольные SQL-команды в конвейер агрегации через REST-конечную точку /api/content/aggregate/{model}.
Этот недостаток позволяет злоумышленникам:
_state=1) для чтения неопубликованных черновиков.sqlite_master.Следующие шаги демонстрируют, как злоумышленник может обойти фильтр авторизации _state=1.
testcol.title и body.Скриншот: Настройка модели контента testcol

MasterRole), чтобы она имела разрешение ЧТЕНИЕ для модели testcol.Скриншот: Настройка разрешений роли для коллекции

MasterRole. Скопируйте значение ключа (например, API-b8e8...).Скриншот: Настройка API-ключа с ролью доступа на чтение

Public и установите его состояние как ОПУБЛИКОВАНО (зелёный значок).SECRET_DRAFT и установите его состояние как НЕ ОПУБЛИКОВАНО (красный значок).Скриншот: Список элементов, показывающий один опубликованный и один неопубликованный элемент

По умолчанию стандартные API-запросы возвращают только контент с состоянием «Опубликовано». Однако, внедряя SQL в конвейер агрегации, можно обойти фильтр опубликованного контента.
json_extract() и добавляет SQL-комментарий -- для нейтрализации завершающего SQL, конкретно нацеливаясь на предложение WHERE, которое ограничивает результаты только опубликованными элементами.Внедряемое поле:
$title') as _id FROM collections_testcol--
Полный JSON конвейера:
[{"$group": {"_id": "$title') as _id FROM collections_testcol--", "c": {"$sum": 1}}}]
/api/content/aggregate/testcol. Обязательно замените YOUR_API_KEY на ключ, сгенерированный в шаге 2.2:curl "http://localhost:8080/api/content/aggregate/testcol?api_key=YOUR_API_KEY&pipeline=%5B%7B%22%24group%22%3A%20%7B%22_id%22%3A%20%22%24title%27%29%20as%20_id%20FROM%20collections_testcol--%22%2C%20%22c%22%3A%20%7B%22%24sum%22%3A%201%7D%7D%7D%5D"
Как показано на финальном скриншоте ниже, ответ API успешно возвращает элемент SECRET_DRAFT, несмотря на то, что он явно помечен как НЕ ОПУБЛИКОВАННЫЙ. Это подтверждает, что SQL-инъекция обходит основной механизм авторизации приложения и позволяет несанкционированное извлечение данных через API.
Скриншот: Успешное извлечение неопубликованных данных 'SECRET_DRAFT'

В классическом развёртывании headless CMS публичный API-ключ с доступом только на чтение часто встраивается/жёстко прописывается в JavaScript на стороне фронтенда. Используя эту уязвимость через публичную конечную точку API, злоумышленник может:
content.sqlite, включая коллекции, для которых API-ключ не авторизован.sqlite_master для обнаружения всех имён таблиц и их структур.| Дата | Действие |
|---|---|
| 2026-02-28 | Уязвимость обнаружена в ходе авторизованного исследования безопасности |
| 2026-03-02 | Отчёт отправлен поставщику |
| 2026-03-02 | Исправление поставщика -- https://github.com/Cockpit-HQ/Cockpit/commit/b6a0b45c5e8fe16f3027b889583cc3a9127ab4b0 |
| 2026-03-09 | Патч выпущен в версии 2.13.5 -- https://getcockpit.com/releases |