
Proof-of-concept che dimostra una XSS memorizzata nel Table Widget di Appsmith che porta a un'escalation verticale dei privilegi e alla completa compromissione dell'admin tramite attacco XSS-to-CSRF.
Proof-of-Concept per l'Escalation of Privileges in Appsmith tramite Stored XSS
Divulgazione: Segnalato originariamente da me tramite GHSA-5hw4-whxv-6794
⚠️ Solo per uso autorizzato in test di penetrazione/ricerca.
| Campo | Valore |
|---|---|
| ID CVE | CVE-2026-30862 |
| Gravità | 🔴 Critica |
| Punteggio CVSS | 9.1 |
| Vettore CVSS | [CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H] |
| CWE | CWE-79, CWE-269, CWE-352 |
| Prodotto Interessato | Appsmith ≤ 1.95 |
| Versione Corretta | 1.96 |
| Advisory | GHSA-5hw4-whxv-6794 |
Una vulnerabilità Stored XSS Critica esiste nel Table Widget (TableWidgetV2). La causa principale è la mancanza di sanitizzazione HTML nella pipeline di rendering dei componenti React, che consente l'interpolazione di attributi dannosi nel DOM. Sfruttando la funzionalità "Invite Users", un attaccante con un account utente normale ([email protected]) può costringere un Amministratore di Sistema a eseguire una chiamata API ad alta privilegi (/api/v1/admin/env), con conseguente Compromissione Completa dell'Account Amministrativo.
1. Causa Principale: Mancanza di Sink di Sanitizzazione dell'Output La vulnerabilità risiede nel motore di rendering del Table Widget
File: app/client/src/widgets/TableWidgetV2/component/cellComponents/BasicCell.tsx
Il componente BasicCell non riesce a sanitizzare i dati quando columnType è impostato su URL o Plain Text. Restituisce valori grezzi forniti dall'utente che vengono direttamente renderizzati come figli React, che il browser interpreta come HTML eseguibile.
Frammento di Codice Vulnerabile (Righe 132-143 e 172-173):
const contentToRender = useMemo(() => {
switch (columnType) {
case ColumnTypes.URL:
// Interpolazione diretta di 'url' in href senza sanitizzazione
return <a href={url} target="_blank">{value}</a>;
default:
return value; // Riga 141: Valore grezzo restituito
}
}, [columnType, url, value]);
// Riga 173: Sink finale dove il contenuto non sanitizzato viene iniettato nel DOM
<Content ref={contentRef}>{contentToRender}</Content>
2. Vettore di Attacco: XSS-to-CSRF tramite Ingegneria Sociale (Funzionalità Invite) Sebbene il cookie SESSION sia protetto da HttpOnly, il XSRF-TOKEN è accessibile tramite document.cookie. Poiché Appsmith consente a qualsiasi utente di "Invite" altri nella propria app, un attaccante può utilizzarlo come meccanismo di consegna per eseguire una Cross-Privilege Request Forgery (CPRF) all'interno della sessione attiva dell'Amministratore.
Passo 1: Verifica della Vulnerabilità XSS
Accedi con un account utente normale: [email protected].
Crea una nuova applicazione e aggiungi un Table Widget.
Nella proprietà Table Data, inietta quanto segue:
[{ "id": 1, "payload": "" }]
-- Passo 2: Weaponizzazione (Compromissione Completa dell'Admin)
[email protected], aggiorna il Table Data con il seguente payload progettato per modificare l'ambiente amministrativo:[
{
"id": 1,
"Status": "System Update Required",
"payload": "alert('Admin Privileges Granted to [email protected]'));\">"
}
]
Utilizza la funzionalità "Share" per invitare l'Amministratore di Sistema ([email protected]) all'app. Questo costringe l'Admin a visualizzare la tabella dannosa all'apertura dell'invito.
Una volta che l'Admin avvia l'app, lo script viene eseguito in background. Legge il XSRF-TOKEN dell'Admin e invia una richiesta PUT per aggiungere [email protected] alla whitelist amministrativa.
Risultato: Accedi di nuovo come [email protected]. Ora avrai pieno accesso alle Impostazioni Admin e a tutte le configurazioni dell'istanza.
Tipo di Vulnerabilità: Stored XSS / Escalation of Privileges Verticale.
Gravità: 9.1 (Critica) | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H
Rischio: Compromissione completa dell'istanza Appsmith. Gli attaccanti ottengono accesso a variabili d'ambiente sensibili, credenziali del database e la capacità di modificare qualsiasi applicazione all'interno dell'istanza.
Sanitizzare i Sink: Avvolgere tutte le uscite dinamiche in BasicCell.tsx e nei componenti correlati con DOMPurify.sanitize().
CSP Rafforzata: Implementare una policy connect-src rigorosa per prevenire chiamate API non autorizzate agli endpoint amministrativi da payload XSS.
https://github.com/user-attachments/assets/206a10e4-1619-4887-a552-99761baa0a29