
CVE-2026-39275 - XSS almacenado que conduce a la toma de cuentas en Cockpit CMS
| ID CVE | CVE-2026-39275 |
| Vulnerabilidad | Cross-Site Scripting Almacenado (XSS) → Toma de Control de Cuenta |
| CWE | CWE-79 |
| Afectado | Cockpit CMS <= 2.13.5 |
| Corregido | d70dc50 |
| CVSS 3.1 | 8.4 (AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N) |
| Reportado por | Rohith - Consultor de Seguridad @ SecurifyAI |
Una vulnerabilidad de XSS almacenado en la vista de lista de colecciones de contenido permite a cualquier usuario con acceso de escritura de contenido (una clave API o una sesión de editor autenticado) inyectar JavaScript arbitrario que se ejecuta en el navegador de cualquier administrador o editor que vea la lista de elementos de la colección afectada.
Los tokens de sesión de Cockpit son completamente accesibles desde JavaScript: la cookie de sesión se establece sin la bandera HttpOnly, y el JWT CSRF está expuesto en la variable global App.csrf y en el atributo data-csrf en <html>. Esto permite que el script inyectado lea ambos tokens y los reproduzca externamente, anulando la protección CSRF y permitiendo el secuestro completo de sesión y la toma de control de cuenta.
Las salidas del método render() de los campos se pasan a la directiva v-html de Vue sin codificación de salida.
| Archivo | Línea(s) | Rol |
|---|---|---|
modules/App/assets/vue-components/fields/field-tags.js | 25 - 34 | Renderizador de etiquetas - sin codificación |
modules/App/assets/vue-components/fields/field-select.js | 26 | Renderizador de selección - sin codificación |
modules/Content/views/collection/items.php | 149 | sumidero v-html |
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
}
}'
Un administrador o editor navega a /content/collection/items/posts. El renderizador de etiquetas devuelve la cadena almacenada, v-html la analiza en un elemento `` real, el src falso falla y el manejador onerror se activa.
Ambos tokens ahora son legibles: la cookie de sesión a través de document.cookie y el JWT CSRF a través de App.csrf / document.documentElement.getAttribute('data-csrf'). Un payload armado exfiltra ambos:

El atacante rejuega la cookie robada y el token CSRF, obteniendo acceso completo de administrador autenticado, y luego puede crear cuentas de administrador, cambiar credenciales o modificar contenido.
Un editor con pocos privilegios (o cualquier titular de clave API de escritura de contenido) escala a administrador completo. El payload se almacena y se activa para cada administrador/editor que vea la lista, convirtiéndolo en un compromiso persistente y multi-víctima.
Corrección principal: sanitizar la salida del render antes de que llegue a v-html utilizando el helper existente App.utils.stripTags().
field-tags.js:
value = App.utils.stripTags(value); // sanitize before v-html
field-select.js:
return App.utils.stripTags(value); // sanitize before v-html
Defensa en profundidad: endurecer la cookie de sesión:
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1); // over HTTPS
ini_set('session.cookie_samesite', 'Strict');
HttpOnly por sí solo es insuficiente: el XSS aún puede actuar dentro del contexto autenticado del navegador de la víctima, por lo que la codificación de salida es la corrección esencial.
| Fecha | Evento |
|---|---|
| 2026-03-29 | Vulnerabilidad reportada a los mantenedores de Cockpit CMS |
| 2026-03-29 | Corrección publicada por los mantenedores |
| 2026-04-04 | CVE solicitado |
| 2026-06-23 | CVE-2026-39275 asignado |
<pub date> | Divulgación pública |
Este material se publica con fines educativos y defensivos siguiendo una divulgación coordinada. Úselo solo contra sistemas que posea o que tenga autorización explícita para probar.