
Доказательство концепции эксплуатации для CVE-2026-8161, уязвимости типа «отказ в обслуживании» в multiparty multipart parser, демонстрирующей загрязнение прототипа, приводящее к необработанному исключению и сбою.
Доказательство концепции CVE-2026-8161 (Multiparty)
[email protected] и более ранние версии уязвимы к отказу в обслуживании из-за необработанного исключения.
Парсер сохраняет загруженные поля и файлы в обычных JavaScript-объектах и небезопасно различает ключи, принадлежащие парсеру, от унаследованных свойств объекта. Специально сформированное имя multipart-поля может заставить парсер прочитать неожиданные значения из цепочки прототипов и завершиться с ошибкой при обработке загрузки.
Любой сервис, принимающий multipart-загрузки через уязвимые версии multiparty, может быть затронут.
Проблема возникает потому, что fields и files являются обычными JavaScript-объектами, но используются как безопасные карты «ключ-значение» для имён, контролируемых пользователем.
var fieldsArray = fields[name] || (fields[name] = [])
fieldsArray.push(value)
var filesArray = files[name] || (files[name] = [])
filesArray.push(file)
Проблема в том, что fields[name] и используют обычный поиск свойств JavaScript. Для обычных объектов такой поиск может вернуть унаследованные свойства из цепочки прототипов вместо только тех значений, которые хранятся в самом объекте.
files[name]Когда name равно __proto__, JavaScript может разрешить его через цепочку прототипов и вернуть унаследованный объект прототипа вместо undefined. Поскольку это значение является истинным, присваивание по умолчанию пропускается, и парсер никогда не создаёт настоящий массив для этого поля.
Патч исправляет это, доверяя только ключам, которые принадлежат непосредственно объекту:
var filesArray = Object.prototype.hasOwnProperty.call(files, name)
? files[name]
: undefined
Затем парсер добавляет значение только тогда, когда сохранённое значение действительно является массивом, в противном случае он инициализирует новый:
if (Array.isArray(filesArray)) {
filesArray.push(file)
} else {
files[name] = [file]
}
Когда .push() вызывается для значения, которое не является массивом, выбрасывается TypeError. Поскольку это происходит внутри асинхронного процесса парсинга Multiparty, обычная обработка ошибок на стороне вызывающего кода может не перехватить её, что позволяет исключению завершить процесс.
Object.prototype.hasOwnProperty.call(...).Запустите среду mocklab и отправьте тестовую нагрузку на обе цели:
docker compose up -d
python3 secdos.py -u http://localhost:8080/api/submit
python3 secdos.py -u http://localhost:8081/api/submit
Уязвимая цель завершится с ошибкой и вернёт [PASS]. Исправленная цель безопасно обработает запрос и вернёт [FAIL].
При повторном запуске против уязвимого сервера сначала перезапустите его
Сборка исправленного образа из dockerfile требует аргумент сборки PATCHED=1