
Prueba de concepto que demuestra XSS almacenado en el widget de tabla de Appsmith, que conduce a una escalada vertical de privilegios y a la toma total del control de administrador mediante un ataque XSS-a-CSRF.
Prueba de Concepto para Escalada de Privilegios en Appsmith mediante XSS Almacenado
Divulgación: Reportado originalmente por mí a través de GHSA-5hw4-whxv-6794
⚠️ Solo para pruebas de penetración/investigación autorizadas.
| Campo | Valor |
|---|---|
| ID CVE | CVE-2026-30862 |
| Severidad | 🔴 Crítica |
| Puntuación CVSS | 9.1 |
| Vector 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 |
| Producto Afectado | Appsmith ≤ 1.95 |
| Versión Parcheada | 1.96 |
| Aviso | GHSA-5hw4-whxv-6794 |
Existe una vulnerabilidad de XSS Almacenado Crítico en el Table Widget (TableWidgetV2). La causa raíz es la falta de saneamiento de HTML en el pipeline de renderizado de componentes React, lo que permite interpolar atributos maliciosos en el DOM. Aprovechando la función "Invite Users", un atacante con una cuenta de usuario normal ([email protected]) puede obligar a un Administrador del Sistema a ejecutar una llamada API de altos privilegios (/api/v1/admin/env), resultando en una Toma de Control Total de la Cuenta Administrativa.
1. Causa Raíz: Falta de Sink de Saneamiento de Salida La vulnerabilidad reside en el motor de renderizado del Table Widget
Archivo: app/client/src/widgets/TableWidgetV2/component/cellComponents/BasicCell.tsx
El componente BasicCell no sanean los datos cuando columnType está configurado como URL o Plain Text. Devuelve valores crudos proporcionados por el usuario que se renderizan directamente como hijos de React, que el navegador interpreta como HTML ejecutable.
Fragmento de Código Vulnerable (Líneas 132-143 y 172-173):
const contentToRender = useMemo(() => {
switch (columnType) {
case ColumnTypes.URL:
// Interpolación directa de 'url' en href sin saneamiento
return <a href={url} target="_blank">{value}</a>;
default:
return value; // Línea 141: Valor crudo devuelto
}
}, [columnType, url, value]);
// Línea 173: Sink final donde el contenido no saneado se inyecta en el DOM
<Content ref={contentRef}>{contentToRender}</Content>
2. Vector de Ataque: XSS a CSRF mediante Ingeniería Social (Función Invite) Aunque la cookie SESSION está protegida por HttpOnly, el XSRF-TOKEN es accesible a través de document.cookie. Dado que Appsmith permite a cualquier usuario "Invitar" a otros a su aplicación, un atacante puede usar esto como mecanismo de entrega para ejecutar una Cross-Privilege Request Forgery (CPRF) dentro de la sesión activa del Administrador.
Paso 1: Verificación de la Vulnerabilidad XSS
Inicie sesión con una cuenta de usuario normal: [email protected].
Cree una nueva aplicación y agregue un Table Widget.
En la propiedad Table Data, inyecte lo siguiente:
[{ "id": 1, "payload": "" }]
-- Paso 2: Armamento (Toma de Control Total del Administrador)
[email protected], actualice el Table Data con el siguiente payload diseñado para modificar el entorno administrativo:[
{
"id": 1,
"Status": "System Update Required",
"payload": "alert('Admin Privileges Granted to [email protected]'));\">"
}
]
Use la función "Share" para invitar al Administrador del Sistema ([email protected]) a la aplicación. Esto obliga al Administrador a ver la tabla maliciosa al abrir la invitación.
Una vez que el Administrador abre la aplicación, el script se ejecuta en segundo plano. Lee el XSRF-TOKEN del Administrador y envía una solicitud PUT para agregar [email protected] a la lista blanca administrativa.
Resultado: Inicie sesión nuevamente como [email protected]. Ahora tendrá acceso completo a la Configuración de Administrador y a todas las configuraciones de la instancia.
Tipo de Vulnerabilidad: XSS Almacenado / Escalada Vertical de Privilegios.
Severidad: 9.1 (Crítica) | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H
Riesgo: Compromiso completo de la instancia de Appsmith. Los atacantes obtienen acceso a variables de entorno sensibles, credenciales de base de datos y la capacidad de modificar cualquier aplicación dentro de la instancia.
Saneamiento de Sinks: Envuelva todas las salidas dinámicas en BasicCell.tsx y componentes relacionados con DOMPurify.sanitize().
CSP Reforzado: Implemente una política estricta de connect-src para prevenir llamadas API no autorizadas a endpoints administrativos desde payloads XSS.
https://github.com/user-attachments/assets/206a10e4-1619-4887-a552-99761baa0a29