
CVE-2026-39275 - Stored XSS Leading to Account Takeover in Cockpit CMS
Примечание: Ответственно раскрыто и исправлено разработчиками Cockpit CMS до публикации.
| Идентификатор CVE | CVE-2026-39275 |
| Уязвимость | Хранимая межсайтовая перезапись сценариев (XSS) → Захват учетной записи |
| CWE | CWE-79 |
| Затронутые версии | Cockpit CMS <= 2.13.5 |
| Исправлено в | d70dc50 |
| CVSS 3.1 | 8.4 (AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N) |
| Сообщивший | Rohith - Консультант по безопасности @ SecurifyAI |
Уязвимость хранимой XSS в представлении списка коллекций контента позволяет любому пользователю с правом записи контента (API-ключ или сессия аутентифицированного редактора) внедрить произвольный JavaScript, который выполняется в браузере любого администратора или редактора, просматривающего список элементов затронутой коллекции.
Сессионные токены Cockpit полностью доступны из JavaScript — файл cookie сессии устанавливается без флага HttpOnly, а CSRF JWT раскрывается в глобальной переменной App.csrf и атрибуте data-csrf на <html>. Это позволяет внедренному скрипту прочитать оба токена и воспроизвести их извне, обходя защиту CSRF и позволяя полный перехват сессии и захват учетной записи.
Выводы поля render() передаются директиве v-html Vue без кодирования выходных данных.
curl -X POST "http://localhost:8080/api/content/item/posts" \
-H "Content-Type: application/json" \
-H "api-key: USR-<attacker-api-key>" \
-d '{
"data": {
"title": "Innocent Looking Post",
"tags": [
"",
""
],
"body": "Just a regular post.",
"_state": 1
}
}'
Администратор или редактор переходит на /content/collection/items/posts. Рендерер тегов возвращает сохраненную строку, v-html преобразует её в реальный элемент ``, фиктивный src не загружается, и срабатывает обработчик onerror.
Теперь оба токена можно прочитать — файл cookie сессии через document.cookie и CSRF JWT через App.csrf / document.documentElement.getAttribute('data-csrf'). Вредоносная полезная нагрузка извлекает оба:
Злоумышленник воспроизводит украденный cookie и CSRF-токен, получая полный аутентифицированный доступ администратора — и может затем создавать учетные записи администраторов, изменять учетные данные или модифицировать контент.
Редактор с низким уровнем привилегий (или любой обладатель API-ключа на запись контента) повышает свои права до полного администратора. Полезная нагрузка сохраняется и срабатывает для каждого администратора/редактора, просматривающего список, что делает её постоянной компрометацией многих жертв.
Основное исправление — санитизация вывода рендерера перед передачей в v-html с помощью существующего вспомогательного метода App.utils.stripTags().
field-tags.js:
value = App.utils.stripTags(value); // санитизация перед v-html
field-select.js:
return App.utils.stripTags(value); // санитизация перед v-html
Защита в глубину — ужесточение cookie сессии:
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1); // через HTTPS
ini_set('session.cookie_samesite', 'Strict');
Одного HttpOnly недостаточно — XSS все еще может действовать в контексте аутентифицированного браузера жертвы — поэтому кодирование выходных данных является обязательным исправлением.
| Дата | Событие |
|---|---|
| 2026-03-29 | Уязвимость сообщена разработчикам Cockpit CMS |
Данный материал опубликован в образовательных и защитных целях после скоординированного раскрытия. Используйте только против систем, которыми вы владеете или на тестирование которых у вас есть явное разрешение.
| Файл |
|---|
| Строка(и) |
|---|
| Роль |
|---|
modules/App/assets/vue-components/fields/field-tags.js | 25 - 34 | Рендерер тегов - без кодирования |
modules/App/assets/vue-components/fields/field-select.js | 26 | Рендерер выбора - без кодирования |
modules/Content/views/collection/items.php | 149 | Приемник v-html |
| 2026-03-29 |
| Исправление выпущено разработчиками |
| 2026-04-04 | Запрошен CVE |
| 2026-06-23 | Присвоен CVE-2026-39275 |
<pub date> | Публичное раскрытие |