
Element Web v1.12.29 - Alta - Remoto - XSS - O link navigation.json do Univention ICS torna-se um href de menu javascript:
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · element-ics-javascript
Element Web v1.12.29 - Element / New Vector
Classe: XSS Alcance: Remoto
O módulo de banner do Univention busca o ICS navigation.json, aceita o link de cada entrada como z.string() sem verificação de esquema, e Menu.tsx coloca essa string em um <a href> estilizado. A configuração estática do menu usa z.url() para link_url. O caminho do ICS não. A pré-visualização de URL no mesmo pin já rejeita javascript: (previewFromBundle, GHSA-9r5h). Este não é o app.element.io padrão. Ele precisa de modules/banner com menu.type univention, além de um ICS em que o deploy confie.
Qualquer pessoa que possa alterar esse navigation.json planta javascript: ou data:. Um usuário autenticado que abre o menu do banner e clica no item executa script na origem do Element.
| ID | sem CVE ainda |
| CWE | CWE-79 / CWE-20 |
| CVSS | Médio: 6.8 CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N |
| Produto | Element Web |
| Afetado | v1.12.29 tag v1.12.29 (2d90d6b7b601ecb9ccdf81239a43b4396b4b0c9e). Restrito: banner Univention + ICS. |
| Autenticação | Operador do ICS / comprometimento do ICS. A vítima é um usuário autenticado que clica no item do menu. |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Comprometer ou operar o ICS em que o deploy do Element confia. Colocar uma URL javascript: (ou data:) no navigation.json. Aguardar que um usuário autenticado abra o menu do banner e clique no item. Isso é tomada de conta do Matrix: token de acesso, crypto store, a sessão. Não é RCE no SO. O Desktop ainda tem nodeIntegration desativado e um sandbox.
| Privilégio | Método / sink | Recon / integridade / disponibilidade | Comprovado em lab ou inferido |
|---|---|---|---|
Renderizar um <a href="javascript:…"> do menu do banner na origem do Element | ICS navigation.json entries[].link -> navigationToConfig link_url -> Menu.tsx LinkButton href={link.link_url} | Integridade do DOM do menu | Comprovado em lab. O link mock do ICS javascript:ELEMENT-ICS-JAVASCRIPT-WITNESS tornou-se esse href. O link https do portal ainda foi renderizado |
| Executar script como a origem do Element após um clique | A vítima clica no item do menu (UI:R) | Integridade | Inferido a partir do sink do href. O lab não conduziu um clique de navegador nem roubou um token Matrix ativo |
| Ler o token de acesso do Matrix / crypto store (tomada de conta) | Script na origem vs localStorage / sessão IndexedDB | Recon / integridade | Inferido a partir do XSS na origem do Element. A testemunha do lab é a string do href |
| Navegar a aba do Element no topo para uma página de phishing | iframe sem sandbox do SilentLogin.tsx src={new URL("silent", icsUrl)} | Integridade | Comprovado em lab que o iframe não tem sandbox. Navegação no topo não exercitada |
Mesmo plantio via data: | z.string() aceita qualquer esquema | Integridade | Inferido. O lab plantou apenas javascript: |
Fechado neste pin: app.element.io padrão (sem banner Univention). RCE no SO / LPE (Desktop nodeIntegration: false, sandbox, contextIsolation). XSS no HTML da timeline. javascript: na pré-visualização de URL (GHSA-9r5h previewFromBundle exige http:/https:). XSS na exportação HTML (GHSA-wqmv). Token de mídia do widget (GHSA-3jm3). O link_url: z.url() do banner estático é configuração do operador, não ICS; z.url() também não é uma allowlist de http/https.
Sobras do mesmo pin: fragment guest wipe, vector: Windows drive-letter.
Fiz o pin do Element Web v1.12.29 após o release do GitHub de 22 de setembro de 2026. A pré-visualização de URL já aprendeu http:/https: da forma difícil. O link do ICS do Univention ainda é z.string(). A configuração estática do menu usa z.url(). O caminho de fetch nunca passa por essa verificação.
Caminhos errados já registrados: tratar o app.element.io padrão como a vítima (o Univention é restrito); tratar z.url() como uma allowlist de esquema (o construtor de URL aceita javascript:); inflar o XSS de clique para RCE no SO. Um reverse shell. Teatro.
Gadget das funções do pin mais um ICS mock navigation.json. Não é um contêiner do Element Web em execução. how=gadget. Aplicar a allowlist http/https da pré-visualização de URL (previewFromBundle) removeu o href javascript e manteve o link https do portal.
python3 element-ics-javascript-Abraxas-Labs.py
ou
cd lab
./run.sh
Alvo apenas http://127.0.0.1:19620. Projeto Compose element-ics-javascript. A stack é desmontada após a execução.
SUCCESS element-ics-javascript how=gadget href-scheme=javascript menu-a-javascript=yes allowlist-rejects=yes silent-no-sandbox=yes ELEMENT-ICS-JAVASCRIPT-WITNESS
Aplicar allowlist de http: e https: no link do ICS da mesma forma que previewFromBundle faz. Rejeitar javascript:, data: e outros esquemas antes do href=. Colocar o iframe silencioso em sandbox (sandbox="" ou pelo menos sem allow-top-navigation). Não tratar z.url() como uma allowlist de esquema.
navigation.tsMenu.tsxSilentLogin.tsxpreviewFromBundleGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.