
CVE-2026-39275 - XSS stocké menant à la prise de contrôle de compte dans Cockpit CMS
| Identifiant CVE | CVE-2026-39275 |
| Vulnérabilité | Cross-Site Scripting stocké (XSS) → Prise de contrôle de compte |
| CWE | CWE-79 |
| Affecté | Cockpit CMS <= 2.13.5 |
| Correctif | d70dc50 |
| CVSS 3.1 | 8.4 (AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N) |
| Rapporteur | Rohith - Consultant en sécurité @ SecurifyAI |
Une vulnérabilité de XSS stocké dans la vue liste des collections de contenu permet à tout utilisateur disposant d'un accès en écriture (une clé API ou une session d'éditeur authentifié) d'injecter du JavaScript arbitraire qui s'exécute dans le navigateur de tout administrateur ou éditeur consultant la liste des éléments de la collection concernée.
Les jetons de session de Cockpit sont entièrement accessibles depuis JavaScript - le cookie de session est défini sans le drapeau HttpOnly, et le JWT CSRF est exposé dans la variable globale App.csrf et l'attribut data-csrf sur <html>. Cela permet au script injecté de lire les deux jetons et de les rejouer en externe, contournant ainsi la protection CSRF et permettant le détournement complet de session et la prise de contrôle du compte.
Les sorties de render() des champs sont passées à la directive v-html de Vue sans encodage de sortie.
| Fichier | Ligne(s) | Rôle |
|---|---|---|
modules/App/assets/vue-components/fields/field-tags.js | 25 - 34 | Rendu des tags - pas d'encodage |
modules/App/assets/vue-components/fields/field-select.js | 26 | Rendu de la sélection - pas d'encodage |
modules/Content/views/collection/items.php | 149 | Point d'arrivée 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 administrateur ou éditeur navigue vers /content/collection/items/posts. Le rendu des tags renvoie la chaîne stockée, v-html la parse en un véritable élément ``, le src erroné échoue, et le gestionnaire onerror se déclenche.
Les deux jetons sont désormais lisibles - le cookie de session via document.cookie et le JWT CSRF via App.csrf / document.documentElement.getAttribute('data-csrf'). Une charge utile industrialisée exfiltre les deux :

L'attaquant rejoue le cookie volé et le jeton CSRF, obtenant un accès administrateur authentifié complet - et peut alors créer des comptes administrateur, modifier des identifiants ou modifier du contenu.
Un éditeur à faibles privilèges (ou tout détenteur de clé API d'écriture de contenu) s'élève au rang d'administrateur complet. La charge utile est stockée et se déclenche pour chaque administrateur/éditeur consultant la liste, ce qui en fait une compromission persistante touchant plusieurs victimes.
Correction principale - nettoyer la sortie du rendu avant qu'elle n'atteigne v-html en utilisant l'assistant existant 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
Défense en profondeur - durcir le cookie de session :
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1); // over HTTPS
ini_set('session.cookie_samesite', 'Strict');
HttpOnly seul est insuffisant - le XSS peut toujours agir dans le contexte du navigateur authentifié de la victime - donc l'encodage de sortie est la correction essentielle.
| Date | Événement |
|---|---|
| 2026-03-29 | Vulnérabilité signalée aux mainteneurs de Cockpit CMS |
| 2026-03-29 | Correctif publié par les mainteneurs |
| 2026-04-04 | CVE demandé |
| 2026-06-23 | CVE-2026-39275 attribué |
<pub date> | Divulgation publique |
Ce matériel est publié à des fins éducatives et défensives suite à une divulgation coordonnée. Utilisez-le uniquement contre des systèmes que vous possédez ou que vous êtes explicitement autorisé à tester.