### O desinfectante do jodit incorporado `clean-html` pode ser evitado por um porta- eventos MathML/` ` que esconde um elemento perigoso da marcha do elemento do desinfectante, de modo que um manipulador de eventos sem interação sobrevive ao valor do editor. Quando um aplicativo fornece HTML influenciado pelo atacante para os caminhos de inserção ou configuração do editor, a saída desinfectada ainda contém um ' ` (ou outro manipulador não 'onerror' como 'onfocus'). Um consumidor que renderiza essa saída (`element.innerHTML = editor. value`) executa o manipulador sem interação do usuário. Esta é uma vulnerabilidade de scripts cruzados armazenada, confirmada ao vivo nos `es' enviados 2021 /jodit.min.js` para 4.12.25 e o mais recente 4.12.27 (em Chromium via um cliente 'innerHTML' do lado do consumidor, e no Firefox via saída de contexto de documentos/rendered por servidor; veja a nota de navegação cruzada sob Prova de conceito). ### Detalhes O bypass explora a ordem em que o `clean-html` analisa, caminha e re- serializa o valor. 1. No caminho de valores definido, o plug-in `clean-html` manipula `:foreforeSetNativeEditorValue` (`src/plugins/clean-html/clean-html.ts: 116 `), analisando o valor em um documento inerte: `sandBox.innerHTML = data.value`.
2. Nesse parse, o nidificação de fonte `math > mtext > tabela > mglyph > style` desencadeia o ponto de integração de texto do MathML e as regras de criação de pais: o ` ` é analisado como texto dentro ` ` (texto raw), não como um elemento. O ` ` é adotado para fora, e o ponto de integração de texto MathML ` ` governa o espaço de nomes, então o ` ` nunca se torna um nó de elemento neste parse. 3. Esse desinfectador de valores é o `safeHTML` (`src/core/helpers/html/safe-html.ts: 24 `); ele caminha na árvore, mas age apenas sobre elementos (o portão `Dom.isElement` em `: 39 `) e corre contra a análise- 1 ` sandBox`, no qual o ` ` é um texto bruto, não um elemento. Então ` removeAllEventAttributes` (a faixa completa `on*` em `safe-html.ts: 76 `) não tem nenhum elemento para limpar e o manipulador passa por ela. O manipulador `onAntesDeSetNativeEditorValue` executa `safeHTML` na análise- 1 a árvore tanto antes como depois de capturar o valor, então nem passar nunca vê o ` ` como um elemento. 4. O valor capturado (`data. value = sandBox.innerHTML`) é então atribuído ao editável, um segundo parse, que põe o ` ` fora de ` ` e para o espaço de nomes HTML como um elemento vivo com o seu manipulador intacto. O serialize-reparse move o elemento através da árvore e dos espaços de nomes: ``` ANTES - analisar 1 (SandBox): o é texto [MathML] [MathML] [HTML] ponto de integração: análises de conteúdo como HTML [HTML] texto " " é RAWTEXT, não um elemento [HTML].
APÓS - editor. valor (re-parsed): o é hidratado fora do estilo>, ao vivo [HTML] [MathML] [MathML] [MathML] [MathML] (agora vazio) [HTML] seus fogos de manipulador [HTML] ```` 5. `editor.value` agora carrega aquele elemento vivo. O passe de valores definido (Pasos) 1 - 4 ) apenas caminhava o parse- 1 `sandBox` e nunca o vê; o outro desinfectante, o visitante em mudança (`visiteNodeWalker` via um `LazyWalker`, `clean-html.ts': 56 `/`: 70 "), chega ao elemento iizado, mas o filtro "satizeAttributes" chama "satizeHTMLElement" (`safe- html.ts: 139 `), que tira `onerror` somente - nunca lê a bandeira `removeEventAtributes` `sanitizeAtributes` passa por ela (`sanitize-attributes.ts: 30 `), para que nunca execute a faixa completa ` on * '. Então `onload`, `onfocus`, e todo outro manipulador não 'onerror` nunca é removido e persiste em `editor.value` permanentemente. (`onerror` é o manipulador que o limpador remove, mas somente após um ~ 300 Janela ms na qual também dispara.) Os dois pontos de código (jodit 4.12.27 ): ``` js // 1. clean-html.ts onBeforeSetNativeEditorValue - o passe de valor SYNCHRONOUS é executado na análise- 1 sandBox: sandBox.innerHTML = data. value; //: 128 analisar 1: o operador esconde o elemento como texto raw este.j.e.fire('safeHTML', sandBox); //: 129 safeHTML element-walk falha o rawtext element data.value = sandBox. innerHTML; //: 130 valor capturado; re- analisando- o para os lifests editável o elemento ao vivo safeHTML( sandBox, { safeJavaScriptLink: true, removeOnError: true }); //: 131 re- executa no Mismo parse- 1 sandBox, nunca no valor capturado.
// 2. o filtro ASYNC on- change (LazyWalker) atinge o elemento izado, mas apenas tira onorro: sanitizeHTMLElement( nodeElm, { /*... */ removeEventAtributes: opts. removeEventAtributes }); // sanitize- atributes.ts: 30 - passa a função de exportação de bandeira completa sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = { /*... */ }) { // safe- html.ts: 139 - nunca desestrutura removeEventAttributes se (removeOnError & & elm. hasAttribute('onerror')) atr(elm, 'onerror', null); // onerror SOMENTE; onload / onfocus /... são deixados ao vivo } ``` Todas as quatro camadas são necessárias: remover qualquer um dos 'math' + o ponto de integração, 'table', a fenda `mglyph`, ou o elemento de texto bruto faz com que o manipulador seja tirado do jodit (substitutos por fenda estão sob as variantes do Carrier). O porta-aviões de quatro camadas é necessário apenas no 4.11.2 e depois. jodit 4.11.2 adicionado `cleanHTML. removeEventAttributes` (a faixa completa de valor 'on*'); antes dele (todos 3.x e 4.0 através 4.10.x) o desinfectante apenas removeu `onerror`, por isso, nessas versões um manipulador simples não `onerror` como ` ` sobrevive diretamente `editor.value` sem suporte (confirmado ao vivo no 3.24.9, 4.0.1, 4.2.27 ). Ligado 4.11.2 e, mais tarde, o valor definido arrasta o manipulador nu, então o portador é necessário para escondê-lo como ` ` texto bruto passado que caminha; e porque o limpador de mudança remove apenas `onerror` (Passo 5 ), um manipulador não "onerror" sobrevive em todo o alcance.
O bypass não é específico para o configurador de valores. A mesma operadora sobrevive a clean-html através de `editor.value = X`, `editor.setEditorValue(X)` e `editor.s.insertHTML(X)` (a própria documentação do Jodit da API usa- se para plug-ins e botões personalizados). Isto é distinto dos avisos XSS conhecidos do jodit: CVE- 2023 - 42399 (GHSA- 95 xr- cq 6 h- vwr 3 ) é um problema de sistema de URL 'iframe[src]' corrigido em um 4.0.0 beta, e CVE- 2022 - 23461 (GHSA- 42 hx- vrxx- 5 r 6 v) é uma desanistação de ` onerror` em `<= 3.24.2 `. Nenhum dos dois envolve este parse- 1 o mecanismo rawtext-hoist, e uma busca do rastreador de problemas para mglyph / mathml / mutação / "valor xss" não encontra nenhum relatório prévio. ### Prova do conceito Configuração padrão. Atribuir a carga útil, lê- a de volta, tornando- a da forma como um consumidor faria: ```js const editor = Jodit.make('#editor'); editor.valor = ' ';.
// editor. valor (a saída desinfectada, armazenada) agora contém um manipulador ao vivo, e persiste (como qualquer manipulador // não- onorral, não é removido pelo limpador on- change do jodit): // // // document.getElementById('view').innerHTML = editor. valor; // um consumidor renderiza o valor salvo // -> o 1 x 1 gif loads, onload fire alert(document. domain), sem interação ``` Navegador cruzado: `editor. value` carrega o ' ' ao vivo em ambos os Blink e Gecko, mas o modo de análise do consumidor decide a execução. O cromo dispara sob o 'element.innerHTML' e o 'parsing' de documentos, o Firefox dispara somente sob o 'parsing' de documentos (representação do lado do servidor, `document.write', ` '), porque sob `innerHTML` Gecko deixa o ` ' no espaço de nomes MathML, inerte. Não é necessário o iframe: um consumidor simples `innerHTML` basta no Chromium, qualquer consumidor entregue pelo servidor no Firefox. Controle positivo, mesma execução: um simples ` `, um simples ` `, e um simples ` ` são todos despojados pelo valor-set de passagem síncrona para saída inofensiva, provando que o clean-html está ativo; os mesmos manipuladores passam por apenas quando o carrier-se esconder como texto raw, então o contraste isola o passo de ocultamento de texto raw. (Um simples ` ` é um caso separado - o valor-set de passagem não remove tags; somente o limpador async on-change remove-lo ~ 300 ms mais tarde - então não faz parte deste controle síncrono.)
Variantes do portador: três das quatro camadas aceitam substitutos: o ponto de integração do texto do MathML (`mtext` / `mi` / `ms` / `mn` / `mo`), o filho do ponto de integração (``mglyph` / `malignmark`), e o elemento de texto bruto (`estilo` / `xmp` / `noembed` / `script` / `plaintext`; `title` / `textarea` / `noscript` não funcionam). `math` e `table' não têm substitutos funcionais. O elemento oculto não se limita ao ` `, e qualquer manipulador não 'onerror' persiste permanentemente. A listagem de blocos de nomes de elementos não fechará isso. ### Impacto Logado XSS sem interação do usuário, na configuração padrão, nos caminhos de entrada que o próprio 'clean-html' do jodit é responsável por sanear. o próprio conjunto de testes do jodit afirma que este é um limite de saneamento: `src/plugins/clean-html/clean-html.test.js` afirma que `editor.value = ' test '` sanita para ` teste ` (o `onerror` removido) sob a configuração padrão. O operador neste relatório passa aquele mesmo desinfectador de configuração padrão, ainda assim mantém o manipulador ao vivo, derrotando a garantia afirmada. Uma correção anterior em 4.12.21 Endereçado a um XSS armazenado premissa em um aplicativo que re- renderiza ` editor. value` como HTML confiável, assim este modelo de ameaça é reconhecido pelo mantenedor. Precondição: um atacante pode colocar HTML no editor (um papel de submissão de conteúdo) e a saída do editor é mais tarde renderizada. Qualquer integração que liga `valor' ao estado do aplicativo em jodit- react, carregando um documento armazenado anteriormente ou inserindo conteúdo por meio de um plug- in/ botão executará o script do atacante na página da vítima.
### Sugerido correção Remova o elemento gadget na fonte em vez de re- sanitizar a saída. Um ciclo de re-santificação não fecha isto: o ninho da portadora dentro de si próprio superfícies um nível por parse, para que um passe extra seja evitado à profundidade 2, e qualquer tampa fixa N é descartada na profundidade N+ 2 (profundidade generaliza trivialmente). A correção robusta é soltar qualquer elemento HTML- namespace contrabandeado dentro de ` `/` ` fora de um ponto de integração especifica (` `, ` `, ` `, ` `) durante a caminhada do elemento, a mesma abordagem que o DOMPurify 's `_checkValidNamespace` usa. Este é um passe e independente de profundidade. Ele deve correr em ambos os pontos de entrada: o pass de valor síncrono `safeHTML` e o walker on-change (que não chama `safeHTML`). Um teste de regressão afirmando que nenhum `on*` sobrevive a uma ida e volta através de `editor. valor`, incluindo o caso do portador aninhado, bloqueia- o. Registro de aconselhamento: GHSA-rxcw-mc 6 f- 6 hr 3. Identificadores relacionados: CVE- 2026 - 58263.
Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 31 T 19: 12: 40.000 Z e lista a sua última modificação como 2026 - 07 - 31 T 19: 12: 40.000 Z. Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N.
Software afetado e informações de versão: pacote npm jodit — ECOSISTEM: introduzido 0, corrigido 4.12.28. Classificação e evidência: identificadores de fraqueza CWE- 79, CWE- 83. O registro contém 5 suporte de referências nestes tipos: WEB, AVISO, EMBALAGAMENTO.