Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-34212 — Docmost ha accettato un URL javascript: all'interno di un nodo allegato, lo ha preservato attraverso l'archiviazione e il rendering, e lo ha ritrasformato in un'ancora cliccabile nell'origine di Docmost. | Kitploit
Strumenti/GitHubGitHub/0xmrma/cve-2026-34212
Analisi delle VulnerabilitàExploitSicurezza WebPenetration TestingPaper e RicercaApprendimento e Formazione
GitHub0xmrma/cve-2026-34212

CVE-2026-34212

Docmost ha accettato un URL javascript: all'interno di un nodo allegato, lo ha preservato attraverso l'archiviazione e il rendering, e lo ha ritrasformato in un'ancora cliccabile nell'origine di Docmost.

Vedi Repository
1 mese faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2026-34212

Docmost accettava un URL javascript: all'interno di un nodo allegato, lo conservava attraverso lo storage e il rendering, e lo trasformava di nuovo in un anchor cliccabile nell'origine di Docmost.

Introduzione

Ho identificato, divulgato responsabilmente e riprodotto un problema di XSS memorizzato ad alta gravità in Docmost, la piattaforma di documentazione collaborativa open-source.

Il sito ufficiale di Docmost la presenta come un wiki on-premises pronto per l'uso enterprise con oltre 3 milioni di download, e afferma che è utilizzata da team di organizzazioni tra cui Vilnius City, Bechtle, il Governo Australiano, la Croce Rossa e ETS Quebec.

Il bug si trovava in un punto facile da trascurare nei sistemi rich-text:

non nell'estensione dei link ordinari, ma in un tipo di nodo personalizzato separato usato per gli allegati di file.

Stavo esaminando la pipeline dell'editor con una domanda molto specifica in mente:

se i link normali bloccano gli URL javascript:, i nodi allegato applicano la stessa regola prima di raggiungere un sink di anchor?

Nelle versioni vulnerabili, non lo facevano.

Docmost accettava un nodo allegato malevolo nel JSON della pagina, conservava il suo attributo url inalterato, e successivamente rendeva quel valore in un elemento <a href="javascript:..."> cliccabile.

Quel problema è diventato CVE-2026-34212.

Docmost: docmost/docmost
Advisory: GHSA-cf68-cff9-hq4w
CVE: CVE-2026-34212
Corretto in: v0.71.0

photo0

Catena d'attacco

URL del nodo allegato controllato dall'attaccante -> JSON della pagina accettato e memorizzato inalterato -> rendering HTML/React trasforma quell'URL in href di anchor -> la vittima clicca sull'azione dell'allegato -> JavaScript controllato dall'attaccante viene eseguito nell'origine di Docmost


Cosa Fa Questa Parte di Docmost

Docmost memorizza il contenuto della pagina in un formato JSON compatibile con ProseMirror/Tiptap.

Questo modello di contenuto include nodi blocco personalizzati per cose come:

  • immagini
  • diagrammi
  • embed
  • allegati

Il nodo allegato memorizza campi come:

  • url
  • name
  • mime
  • size
  • attachmentId

Il server accetta il contenuto della pagina in diversi formati:

  • json
  • markdown
  • html

e lo normalizza in JSON ProseMirror prima di memorizzarlo.

Ciò significa che ogni tipo di nodo che può trasportare un URL fa parte di un confine di fiducia diretto.

Se uno di questi tipi di nodo alla fine viene reso in un <a href>, la gestione dello schema URL non è opzionale. Fa parte del modello di sicurezza.


Perché Valeva la Pena Esaminare Questa Superficie

Le estensioni personalizzate dell'editor sono una frequente fonte di deriva di sicurezza.

Il sistema di base può già sapere come gestire correttamente gli URL pericolosi, ma ogni nodo personalizzato deve comunque riapplicare le stesse regole ai propri sink.

Questo crea una strategia di revisione prevedibile:

  • trovare ogni tipo di nodo che memorizza un campo simile a un URL
  • tracciare dove quel campo viene accettato
  • tracciare dove quel campo viene renderizzato
  • confrontare il suo comportamento di sanitizzazione con la normale gestione dei link della piattaforma

È esattamente quello che ha esposto questo bug.

La normale estensione dei link di Docmost già trattava javascript: come pericoloso.

Il suo nodo allegato no.

Una volta vista questa asimmetria, la domanda di sicurezza diventa ovvia:

posso persistere un nodo allegato il cui url è javascript: e ottenerlo renderizzato di nuovo in un anchor attivo?

La risposta è stata sì.


Causa principale

La causa principale era una sanitizzazione inconsistente degli URL tra i tipi di nodo di contenuto.

Il percorso del contenuto lato server accettava URL arbitrari degli allegati purché il contenuto complessivo corrispondesse allo schema ProseMirror.

Nella versione vulnerabile:

  • CreatePageDto accettava content?: string | object
  • PageService.parseProsemirrorContent() normalizzava markdown, html, o json
  • il server poi chiamava jsonToNode(prosemirrorJson)
  • se la validazione dello schema passava, il contenuto veniva memorizzato

Quel passaggio di validazione verificava la validità strutturale, non la sicurezza dell'URL.

La parte critica della logica del server vulnerabile era essenzialmente:

root@kitploit:~
prosemirrorJson = content;
jsonToNode(prosemirrorJson);
return prosemirrorJson;
}

Non c'era normalizzazione dello schema URL dell'allegato.

Successivamente, l'estensione dell'allegato renderizzava direttamente il valore controllato dall'attaccante.

Il nodo allegato vulnerabile faceva questo:

```ts
url: {
  default: "",
  parseHTML: (element) => element.getAttribute("data-attachment-url"),
  renderHTML: (attributes) => ({
    "data-attachment-url": attributes.url,
  }),
},

e poi:

root@kitploit:~
[
  "a",
  {
    href: HTMLAttributes["data-attachment-url"],
    class: "attachment",
    target: "blank",
  },
  `${HTMLAttributes["data-attachment-name"]}`,
]

Lato client, la vista del nodo React lo rimpacchettava di nuovo in:

root@kitploit:~
<a href={getFileUrl(url)} target="_blank">

Ma getFileUrl() specializzava solo:

  • URL http assoluti
  • /api/...
  • /files/...

Tutto il resto veniva restituito inalterato.

Quindi un payload come:

root@kitploit:~
javascript:alert(document.domain)

sopravviveva a:

  • memorizzazione JSON
  • validazione dello schema lato server
  • rendering HTML
  • gestione URL lato client

Questo da solo sarebbe già sufficiente per XSS memorizzato.

Ciò che rende la causa principale particolarmente chiara è il punto di confronto.

La normale estensione dei link di Docmost bloccava esplicitamente javascript::

  • rifiutava javascript: in parseHTML()
  • azzerava un href javascript: in renderHTML()

Quindi il prodotto sapeva già che questo schema era pericoloso.

Il nodo allegato semplicemente non applicava la stessa politica.

Ecco perché questo non era "XSS generico nell'editor."

Era un gap nel confine di fiducia specifico del nodo.


Perché Questo è un Problema di Sicurezza, Non Solo una Sanitizzazione Mancante

Questo bug non riguardava solo un'estetica HTML non sicura.

Permetteva a un attaccante in grado di modificare una pagina di persistere un payload malevolo che successivamente sarebbe stato eseguito nell'origine di Docmost quando un altro utente interagiva con l'allegato renderizzato.

Questo è importante perché uno script in-origine può:

  • leggere i dati a cui la vittima ha accesso
  • inviare richieste autenticate come la vittima
  • modificare contenuti che la vittima è autorizzata a modificare
  • abusare di qualsiasi superficie DOM o API esposta alla sessione

Il requisito di un clic non riduce questo a un problema banale.

Il clic fa parte del comportamento normale del prodotto: l'interfaccia utente presenta intenzionalmente l'allegato come un link/icona cliccabile.

Quindi la domanda di sicurezza non è "l'attaccante può forzare JS arbitrario senza alcuna interazione?"

La domanda reale è:

l'applicazione memorizza contenuti malevoli portatori di script controllati dall'attaccante e li presenta successivamente ad altri utenti come un percorso di interazione fidato?

Nelle versioni vulnerabili, lo faceva.

Questo è XSS memorizzato.


Perché lo Sfruttamento Era Pratico

Il percorso di sfruttamento era semplice:

  • qualsiasi utente con diritti di modifica della pagina poteva piantare il payload
  • l'URL malevolo sopravviveva alla memorizzazione inalterato
  • la pagina veniva renderizzata normalmente
  • gli spettatori avevano solo bisogno dell'accesso standard alla pagina
  • un solo clic sull'azione dell'allegato era sufficiente per innescare l'esecuzione

Questo rendeva anche gli utenti con privilegi più elevati obiettivi realistici.

Se un proprietario del workspace, un amministratore o un editor ampiamente fidato visualizzava contenuti controllati dall'attaccante e cliccava sull'azione dell'allegato, lo script dell'attaccante veniva eseguito nel contesto di sessione con privilegi più elevati.

Questo è il punto pratico importante:

il requisito di privilegio dell'attaccante era solo basso. Il livello di privilegio della vittima determinava quanto valore la sessione XSS portava.


Prova di Concetto

Ho validato il problema dal vivo contro Docmost v0.70.3.

La PoC utilizzava solo normali richieste HTTP e le API della pagina dell'applicazione.

Il flusso era:

  1. Accedi come utente che può modificare una pagina.
  2. Crea o seleziona una pagina.
  3. Invia POST /api/pages/update con format: "json" e un nodo allegato il cui url è un payload javascript:.
  4. Richiedi la pagina indietro tramite POST /api/pages/info.
  5. Conferma che il JSON memorizzato contiene ancora l'URL malevolo.
  6. Richiedi la stessa pagina in formato HTML e conferma che il server restituisce un anchor il cui href è ancora javascript:....
  7. Nell'interfaccia utente, uno spettatore che clicca sull'azione dell'allegato renderizzato esegue il payload nell'origine di Docmost.

Il contenuto malevolo minimo era:

root@kitploit:~
{
  "pageId": "<pageId>",
  "content": {
    "type": "doc",
    "content": [
      {
        "type": "attachment",
        "attrs": {
          "url": "javascript:alert(document.domain)",
          "name": "policy.pdf",
          "mime": "application/pdf",
          "size": 1
        }
      }
    ]
  },
  "operation": "replace",
  "format": "json"
}

Il risultato live osservato dal mio test è stato:

  • l'API accettava il nodo allegato malevolo inalterato
  • l'ID della pagina memorizzata era 019d18cf-4212-70b0-894a-fe20080fb0f1
  • POST /api/pages/info restituiva il JSON memorizzato con:
root@kitploit:~
"url": "javascript:alert(document.domain)"
  • POST /api/pages/info con format: "html" restituiva HTML contenente:
root@kitploit:~
<div data-type="attachment" data-attachment-url="javascript:alert(document.domain)" data-attachment-name="policy.pdf" data-attachment-mime="application/pdf" data-attachment-size="1"><a href="javascript:alert(document.domain)" class="attachment" target="blank">policy.pdf</a></div>

Quella risposta HTML è la prova critica.

Non avevo bisogno di affidarmi a un'affermazione vaga del tipo "un browser potrebbe fare qualcosa di interessante."

L'applicazione stessa rendeva l'esatto sink eseguibile.

Una volta che un utente clicca su quel link/icona dell'allegato, il browser esegue l'URL javascript: nell'origine della pagina che lo ha creato.


Perché la PoC È Stata Scelta in Questo Modo

Per XSS guidati dall'editor, gli screenshot da soli sono prove deboli.

Mostrano sintomi, non il fallimento del confine.

Ecco perché ho strutturato la PoC attorno a due checkpoint espliciti:

  1. prova di archiviazione
  2. prova di sink renderizzato

La prova di archiviazione mostrava che il server accettava e conservava lo schema pericoloso.

La prova di sink renderizzato mostrava che l'applicazione trasformava quel valore memorizzato di nuovo in:

root@kitploit:~
<a href="javascript:...">

Questa suddivisione è importante.

Se un prodotto memorizza input pericolosi ma li neutralizza prima di ogni sink, puoi avere un gap di hardening ma non necessariamente un XSS attivo.

Se il prodotto memorizza input pericolosi e successivamente li renderizza in un sink di esecuzione reale, hai la catena completa della vulnerabilità.

Questo è ciò che è successo qui.


Analisi della Correzione

La correzione è stata rilasciata in v0.71.0 e ha affrontato il percorso di sfruttamento renderizzato applicando la sanitizzazione degli URL agli URL degli allegati.

L'estensione dell'allegato ora importa e utilizza sanitizeUrl, includendo:

  • sanitizzazione di data-attachment-url durante il parsing
  • sanitizzazione di data-attachment-url durante il rendering
  • sanitizzazione dell'href dell'anchor

Concettualmente, la patch ha cambiato il nodo allegato da:

  • fidati dell'URL grezzo dell'allegato
  • emetti l'URL grezzo dell'allegato

a:

  • normalizza l'URL dell'allegato prima che diventi parte del nodo renderizzato

Anche l'helper lato client getFileUrl() è stato aggiornato in modo che schemi sconosciuti non passino più inalterati. Nella versione corretta, il percorso di fallback restituisce sanitizeUrl(src) invece di restituire src così com'è.

Questa è una parte importante della correzione perché il design vulnerabile aveva due problemi che si rinforzavano a vicenda:

  • il nodo renderizzava un href grezzo
  • il fallback client trattava schemi sconosciuti come accettabili

La patch ha rimosso entrambe le assunzioni.

Questa è stata una buona correzione per il percorso XSS attivo perché ha riallineato la gestione degli URL degli allegati con il resto del modello di sicurezza dell'editor.

Detto questo, c'è ancora una lezione di hardening più ampia:

la sanitizzazione lato client o al momento del rendering è necessaria qui, ma il rifiuto lato server di schemi pericolosi durante la creazione/aggiornamento della pagina sarebbe un invariante ancora più forte.

Il modello più sicuro a lungo termine è:

  • rifiuta schemi ovviamente pericolosi all'ingestione
  • sanitizza di nuovo ai confini di rendering

La difesa in profondità è importante nei sistemi rich-content.


Casi di Regressione Che Contano

Per una copertura a lungo termine, questi sono i casi che contano di più:

  • aggiornamenti JSON della pagina contenenti attachment.attrs.url = "javascript:..."
  • import HTML contenenti data-attachment-url="javascript:..."
  • il rendering dell'allegato non deve mai emettere href="javascript:..."
  • gli helper di fallback client non devono restituire schemi eseguibili sconosciuti inalterati
  • i nodi allegato e i nodi link normali dovrebbero condividere una politica equivalente sugli schemi URL
  • i percorsi di allegati interni sicuri come /api/files/... e /files/... devono continuare a funzionare normalmente

Il punto chiave è la coerenza.

Se i link normali sono sanitizzati ma i nodi URL personalizzati no, l'editor non ha realmente una politica di sicurezza URL unica.

Ha frammenti, e i frammenti sono dove vivono i bug XSS.


Gravità e Classificazione

L'advisory pubblicato ha classificato questo problema come:

  • CWE-79: Neutralizzazione Impropria dell'Input Durante la Generazione della Pagina Web
  • CVSS v3.1:
root@kitploit:~
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N

Questo si attesta a 7.6 / Alta.

Questa è una classificazione difendibile.

Le proprietà importanti sono:

  • basso requisito di privilegio dell'attaccante
  • payload memorizzato
  • esecuzione nell'origine di Docmost
  • cambio di ambito
  • impatto significativo sulla riservatezza perché lo script può accedere ai dati visibili all'utente nell'app

L'interazione dell'utente rimane richiesta perché la vittima deve attivare il link/icona dell'allegato. Ecco perché UI:R è corretto.

Ma una volta che si verifica quell'interazione, il confine di sicurezza è già fallito molto prima: l'applicazione ha memorizzato uno schema pericoloso e lo ha renderizzato di nuovo in un sink di esecuzione.


Divulgazione

Ho segnalato il problema privatamente tramite GitHub Security Advisories con:

  • analisi della causa principale
  • una PoC HTTP dal vivo
  • prove di archiviazione JSON
  • prove di sink HTML renderizzato
  • un laboratorio di test usa e getta fissato

Il problema è stato accettato, è stato assegnato CVE-2026-34212 e pubblicato il 14 aprile 2026.

L'advisory pubblico attualmente elenca:

  • versione affetta: 0.70.3
  • versione corretta: 0.71.0

La mia validazione dal vivo è stata eseguita su v0.70.3, che corrispondeva alla versione vulnerabile pubblicata.


Cosa Insegna Realmente Questo Bug

La lezione principale qui non è semplicemente "sanitizza gli URL."

Lo sanno già tutti.

La lezione più interessante è:

se un'applicazione ha un tipo di nodo URL sicuro e un tipo di nodo URL non sicuro, quello non sicuro è la politica reale.

I sistemi rich-text spesso accumulano estensioni personalizzate più velocemente di quanto accumulino revisioni di sicurezza.

Questo crea esattamente questo tipo di asimmetria:

  • il percorso di link standard è indurito
  • il percorso degli allegati è trattato come "interno" o "speciale"
  • il percorso speciale diventa silenziosamente il sink XSS più facile

Questo bug mostra anche perché la validazione dello schema non è sufficiente.

jsonToNode() verificava che il contenuto fosse dati ProseMirror strutturalmente validi. Non dimostrava che il contenuto fosse sicuro da renderizzare.

Queste sono domande diverse.

La revisione della sicurezza diventa molto più nitida quando si tengono separate queste domande:

  • questo contenuto è strutturalmente valido?
  • questo contenuto è sicuro da memorizzare?
  • questo contenuto è sicuro da renderizzare in ogni sink?

Il nodo allegato ha superato la prima domanda e fallito la terza.

Ecco come i bug di contenuto memorizzato sopravvivono all'interno di pipeline editor altrimenti ben strutturate.


Punti Chiave

  • Docmost accettava URL grezzi del nodo allegato nel contenuto della pagina.
  • La validazione lato server della pagina controllava la forma dello schema ProseMirror, non la sicurezza dello schema URL.
  • Il nodo allegato vulnerabile renderizzava data-attachment-url e l'href dell'anchor direttamente dall'input controllato dall'attaccante.
  • L'helper client getFileUrl() restituiva schemi sconosciuti inalterati.
  • I nodi di link normali già bloccavano javascript:, ma i nodi allegato no.
  • Un editor con privilegi bassi poteva piantare il payload una volta e prendere di mira spettatori successivi.
  • La PoC dal vivo ha dimostrato sia la persistenza archiviata che il sink eseguibile renderizzato.
  • La correzione in v0.71.0 ha aggiunto la gestione sanitizeUrl al nodo allegato e al percorso di fallback client.

Parole Finali

Questa vulnerabilità non riguardava una stranezza del browser.

Riguardava un nodo di contenuto personalizzato che bypassava le assunzioni di sicurezza URL della propria applicazione.

Docmost accettava un URL di allegato controllato dall'attaccante, lo conservava attraverso lo storage, e poi lo renderizzava di nuovo in un anchor attivo nell'origine dell'applicazione.

Ecco perché è diventato CVE-2026-34212.

La correzione in v0.71.0 ha chiuso pulitamente il percorso XSS attivo, ma la lezione più ampia è quella che vale la pena conservare:

nelle applicazioni incentrate sull'editor, ogni nodo personalizzato che può trasportare un URL è un confine di sicurezza a sé stante, e deve essere revisionato come tale.

Scarica lo strumento