
Element Web v1.12.29 - Élevé - À distance - XSS - Le lien navigation.json d'Univention ICS devient un href de menu javascript:
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · element-ics-javascript
Analyse : https://abraxaslabs.tech/research/element-ics-javascript
Element Web v1.12.29 - Element / New Vector
Classe : XSS Portée : Distante
Le module de bannière Univention récupère le fichier ICS navigation.json, accepte le link de chaque entrée comme z.string() sans vérification de schéma, et Menu.tsx place cette chaîne dans un <a href> stylisé. La configuration statique du menu utilise z.url() pour link_url. Le chemin ICS ne le fait pas. L'aperçu d'URL sur le même commit rejette déjà javascript: (previewFromBundle, GHSA-9r5h). Il ne s'agit pas de l'instance par défaut app.element.io. Cela nécessite modules/banner avec menu.type défini sur univention, ainsi qu'un ICS auquel le déploiement fait confiance.
Quiconque peut modifier ce navigation.json y place javascript: ou data:. Un utilisateur connecté qui ouvre le menu de la bannière et clique sur l'élément exécute du script sur l'origine Element.
| ID | pas encore de CVE |
| CWE | CWE-79 / CWE-20 |
| CVSS | Moyen : 6.8 CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N |
| Produit | Element Web |
| Affecté | v1.12.29 tag v1.12.29 (2d90d6b7b601ecb9ccdf81239a43b4396b4b0c9e). Conditionné : bannière Univention + ICS. |
| Auth | Opérateur ICS / compromission de l'ICS. La victime est un utilisateur connecté qui clique sur l'élément du menu. |
| Licence | GNU Affero GPL v3.0 |
| Labo | 127.0.0.1 uniquement |
Compromettre ou exploiter l'ICS auquel le déploiement Element fait confiance. Placer une URL javascript: (ou data:) dans navigation.json. Attendre qu'un utilisateur connecté ouvre le menu de la bannière et clique sur l'élément. Il s'agit d'une prise de contrôle du compte Matrix : jeton d'accès, stockage cryptographique, la session. Ce n'est pas une RCE au niveau de l'OS. Le client de bureau conserve nodeIntegration désactivé et un bac à sable.
| Privilège | Méthode / sink | Reconnaissance / intégrité / disponibilité | Prouvé en labo ou déduit |
|---|---|---|---|
Rendre un <a href="javascript:…"> de menu de bannière sur l'origine Element | ICS navigation.json entries[].link -> navigationToConfig link_url -> Menu.tsx LinkButton href={link.link_url} | Intégrité du DOM du menu | Prouvé en labo. Le lien ICS simulé javascript:ELEMENT-ICS-JAVASCRIPT-WITNESS est devenu ce href. Le lien HTTPS du portail était toujours rendu |
| Exécuter du script en tant qu'origine Element après un clic | La victime clique sur l'élément du menu (UI:R) | Intégrité | Déduit du sink href. Le labo n'a pas déclenché de clic dans un navigateur ni volé de jeton Matrix réel |
| Lire le jeton d'accès Matrix / le stockage cryptographique (prise de contrôle du compte) | Script dans l'origine vs localStorage / session IndexedDB | Reconnaissance / intégrité | Déduit du XSS sur l'origine Element. Le témoin du labo est la chaîne href |
| Naviguer l'onglet Element vers une page de phishing | iframe non sandboxée de SilentLogin.tsx src={new URL("silent", icsUrl)} | Intégrité | Prouvé en labo que l'iframe n'a pas de sandbox. La navigation de premier niveau n'a pas été exercée |
Même injection via data: | z.string() accepte n'importe quel schéma | Intégrité | Déduit. Le labo n'a injecté que javascript: |
Fermé sur ce pin : app.element.io par défaut (pas de bannière Univention). OS RCE / LPE (Desktop nodeIntegration: false, sandbox, contextIsolation). XSS HTML de la timeline. javascript: dans l'aperçu d'URL (GHSA-9r5h previewFromBundle exige http:/https:). XSS de l'export HTML (GHSA-wqmv). Jeton média de widget (GHSA-3jm3). La bannière statique link_url: z.url() relève de la configuration opérateur, pas de l'ICS ; z.url() n'est pas non plus une liste d'autorisation http/https.
Restes du même pin : effacement de l'invité fragment, lettre de lecteur Windows vector:.
J'ai épinglé Element Web v1.12.29 après la publication GitHub du 22 septembre 2026. L'aperçu d'URL avait déjà appris http:/https: à ses dépens. Le link ICS d'Univention est toujours z.string(). La configuration du menu statique utilise z.url(). Le chemin de récupération ne passe jamais par cette vérification.
Fausses pistes déjà consignées : traiter app.element.io par défaut comme la victime (Univention est protégé par un accès conditionnel) ; traiter z.url() comme une liste d'autorisation de schémas (le constructeur URL accepte javascript:) ; gonfler un XSS au clic en OS RCE. Un reverse shell. Du théâtre.
Gadget des fonctions du pin plus un navigation.json ICS simulé. Pas un conteneur Element Web réel. how=gadget. L'application de la liste d'autorisation http/https de l'aperçu d'URL (previewFromBundle) a supprimé le href javascript et conservé le lien de portail https.
python3 element-ics-javascript-Abraxas-Labs.py
ou
cd lab
./run.sh
Ciblez uniquement http://127.0.0.1:19620. Composez le projet element-ics-javascript. La stack est démontée après l'exécution.
SUCCESS element-ics-javascript how=gadget href-scheme=javascript menu-a-javascript=yes allowlist-rejects=yes silent-no-sandbox=yes ELEMENT-ICS-JAVASCRIPT-WITNESS
Autoriser http: et https: sur le link ICS de la même manière que previewFromBundle. Rejeter javascript:, data: et les autres schémas avant href=. Isoler l'iframe silencieuse dans un bac à sable (sandbox="" ou au minimum sans allow-top-navigation). Ne pas considérer z.url() comme une liste d'autorisation de schémas.
navigation.tsMenu.tsxSilentLogin.tsxpreviewFromBundle