November 26, 2025

"Польза" от уязвимостей

Я вообще не очень люблю ныть, когда у меня нет какого-то конкретного предложения, как починить причину нытья, но тут что-то уже клинит.

Безопасность - это важно. Важно, чтобы все писали свой код так, чтобы его нельзя было просто взломать. Важно, чтобы мы не писали в своем коде NODE_TLS_REJECT_UNAUTHORIZED. Важно, чтобы библиотеки, которые обрабатывают http-запросы, не давали возможности сделать запрос типа GET ../../../etc/passwd.

Но мне кажется, что за последнее время поиск уязвимостей в библиотеках превратился в какой-то абсурд. И мне кажется, что это может превратиться в историю про мальчика, который кричал "волки".

Рандомные примеры критических уязвимостей за последнее время:

Уязвимость в fast-redact

CVE-2025-57319 - жуткая (high severity!) уязвимость в библиотеке, которая предназначена для маскирования данных в объектах. Часто используется в системах логирования. В чем же там суть? Какой-то секьюрити-ресёрчер обнаружил prototype pollution уязвимость в одном из методов библиотеки.

Если передать в него специальным образом сконструированный объект - он может испортить глобальные прототипы всех объектов. В первую секунду ты думаешь "да, действительно неприятно, надо чтобы это исправили". Но потом начинаешь смотреть на пример того, а как же это работает.

Вот пример из самой уязвимости:

// Create a custom object
const customObject = {};

// Craft the instructions to inject a property into Object.prototype
const instructions = [
  {
    target: customObject,
    path: ["polluted", "prototype", "constructor"],
    value: true
  }
];

// Call the vulnerable function with the crafted instructions
require("fast-redact/lib/modifiers").nestedRestore(instructions);

// Verify the exploit
console.log({}.polluted !== undefined ? '[POLLUTION_TRIGGERED]':'');

Кажется, что чтобы это сработало в реальности - нужно либо допустить то, что ваши разработчики - злые буратины, которые пытаются заменить поля типа constructor и prototype в объекте, либо, что еще хуже, они дают возможность внешним пользователям определять "а что же надо удалить из логов". И в том, и в другом случае - вам уже мало что поможет.

Но если посмотреть на уязвимость еще внимательнее - выяснится, что это вообще не реальный API библиотеки - это одна из внутренних функций библиотеки. Она не задокументирована и использоваться вообще не должна. А при использовании нормального внешнего API - даже злые или не очень сообразительные разработчики будут в безопасности:

const fastRedact = require("fast-redact");

const customObject = {};

const redact = fastRedact({
  paths: ['polluted.prototype.constructor'],
});

console.log({}.polluted !== undefined ? '[POLLUTION_TRIGGERED]':''); // выведет ''

Да, сейчас уязвимость перевели в статус disputed. Но какой ценой? Люди уже успели наделать бесчисленное количество issue, форков, кто-то (даже поняв, что проблемы реально нет!) сделал полностью свою реализацию библиотеки.

Принесло ли это пользу человечеству? Что-то я сомневаюсь.

Уязвимость в докер-образах

Наши стандартные докер-образы основаны на node:alpine. В них почти нет лишних пакетов, и они почти совсем пустые - только код приложения и рантайм, чтобы его запустить. Да, иногда даже в совсем базовых пакетах (типа zlib или tzdata) обнаруживаются уязвимости, но это происходит не так уж и часто. Но вот недавно в кучу чатов начали стучаться. "Аларм!", "Все сломалось!", "Мы в опасности!". Сканер нашел в базовых образах критические уязвимости с высоким приоритетом, а именно CVE-2025-64756. Откуда? Из пакета glob. Откуда у нас пакет glob? Из npm. Он является базовой частью node:alpine.

А в чем там вообще уязвимость?

Оказывается, что уязвимость срабатывает только если использовать cli-интерфейс glob, запускать его с флагом --cmd. В таком случае, если злоумышленник создаст файл с именем вида $(touch pwned) и он попадет под glob - то код из имени файла успешно выполнится.

Что ж, действительно уязвимость... Но только если вы используете этот самый пакет glob как cli-утилиту. Ну и если кто-то уже понаписал в вашу файловую систему файлов с командами в их именах (а как он их туда напихал? Он уже вас взломал?)

Но у нас эта библиотека - зависимость зависимости. Никто никогда его не запускал и запускать не будет. Понятное дело, что правильным решением с точки зрения мейнтейнеров glob было бы выделить это все в отдельный пакет (что они и сделали, теперь есть отдельный glob-bin, в котором и уязвимость заодно починили). Да и вообще - виной всему любовь js-разработчиков к пакетам, в которых лежат еще пакеты, а в них - еще пакеты...

Но вот реально, являлась ли эта уязвимость критичной в нашем конкретном случае? На мой взгляд - нет.

Вместо вывода

Проблема не в этих двух конкретных уязвимостях. Это просто то, что я легко вспомнил. Почти все уязвимости, с которыми я сталкивался за последнее время, являются именно такими мутными вещами. Всегда для их эксплуатации надо сделать какие то кривые вещи со стороны самих разработчиков. Всегда для исправления ставятся максимально сжатые сроки - починить их надо уже всера.

Как я в самом начале и сказал - у меня нет какого-то решения. Уязвимости надо искать. Их надо исправлять. Но ощущение, что что-то в этом процессе фундаментально неправильно - не покидает меня.