Черв’як у npm і ваш сайт: крок збірки тепер є межею безпеки
4 серпня 2026 року самовідтворюваний черв’як дістався бібліотеки кешування keyv та її супутників і за кілька годин поширився на сотні npm-пакетів, які разом дають мільярди встановлень на місяць. Це була третя й найбільша хвиля кампанії, відомої під назвою Shai-Hulud, і сталася вона за тиждень до написання цього тексту.
Більшість власників бізнесу вважатиме це проблемою розробників. Це не так, і причина конкретна: якщо ваш сайт зібраний сучасним фронтенд-інструментарієм, то машина, яка його складає, щоразу під час збірки завантажує й виконує код сотень авторів. Крок збірки є межею безпеки, і донедавна майже ніхто так до нього не ставився.
Що саме сталося
Схема була однаковою в усіх хвилях, і її варто зрозуміти один раз, бо деталі пояснюють, чому звичайні запобіжники не допомогли.
- Код виконується до того, як ви скористалися пакетом. Шкідливий код спрацьовує під час встановлення, у хуку життєвого циклу, а не тоді, коли ваш застосунок звертається до бібліотеки. Достатньо просто встановити.
- Він збирає облікові дані. Змінні середовища, ключі до хмари, токени на машині — тобто рівно те, що на складальному сервері є за визначенням.
- Він перевидає сам себе. Викраденим публікаційним токеном він викладає шкідливі версії інших пакетів, які підтримує жертва. Саме це робить його черв’яком, а не інцидентом, і саме тому сотні пакетів падають за години.
- Він виносить дані відкрито. Ранні хвилі складали викрадене в десятки тисяч щойно створених публічних репозиторіїв — шумно, дієво й важко прибирається.
Листопадова хвиля 2025 року скомпрометувала кількасот пакетів і створила десятки тисяч шкідливих репозиторіїв; опубліковані розбори детально описують механізм. Серпнева хвиля 2026 року була ще більшою й дістала пакетів, які майже кожен JavaScript-проєкт підтягує опосередковано.
Незручна арифметика: keyv ніхто не встановлював свідомо. Він приходить як залежність залежності інструмента, який ви таки обрали. Типовий фронтенд-проєкт розгортається в кількасот пакетів, з яких розробник свідомо обрав хіба пʼятнадцять. Кожен із решти здатен виконати код на складальній машині, а кількість мейнтейнерів, компрометація яких дістане до вас, — ті самі кількасот.
Чи стосується це вашого сайту
Три випадки — три різні рівні ризику. Знайдіть свій, перш ніж щось вирішувати.
| Як зібраний сайт | Експозиція | Що має значення |
|---|---|---|
| Класична тема WordPress без збірки | Низька саме для цієї атаки | Ваш ризик — плагіни, а не npm |
| WordPress зі скомпільованою темою або блоками | Реальна, але обмежена часом збірки | Хто збирає, на якій машині, з якими доступами |
| Headless, SPA або JavaScript-фреймворк | Висока | Кожен деплой — свіже встановлення сотень пакетів |
| Конструктор або хостована платформа | Успадкована | Ланцюг постачання платформи тепер і ваш |
Зверніть увагу на другий рядок. Дуже багато сайтів на WordPress мають крок збірки — тема, скомпільована з вихідників, кастомні блоки, зібраний адмінський скрипт, — і запускає його часто підрядник на ноутбуці, де водночас лежать доступи клієнтів. Саме цей ноутбук і є ціллю.
Що справді знижує ризик
Пʼять заходів, упорядкованих за ефектом на одиницю зусиль. Жоден не потребує відділу безпеки.
- Збирайте там, що можна викинути. Контейнер або CI-раннер, який створюється під збірку й знищується після неї. Викрадений доступ корисний лише тоді, коли він є на машині; чистий раннер із вузько обмеженими секретами звужує наслідки будь-якого скомпрометованого пакета до однієї задачі.
- Вимикайте install-скрипти там, де можете. Налаштування пакетного менеджера пропускати хуки життєвого циклу блокує рівно той механізм, яким користуються ці хвилі. Частині пакетів вони справді потрібні, тож ідеться про короткий білий список, а не про глобальний вимикач, — але це перетворює тихе виконання коду на свідоме рішення.
- Фіксуйте lock-файл у репозиторії й відкладайте оновлення. Більшість таких кампаній виявляють за години або дні. Правило не встановлювати версію, опубліковану в останні сімдесят дві години, крім виправлень безпеки, прибирає більшу частину експозиції майже безкоштовно.
- Відмовтеся від довгоживучих публікаційних токенів. npm відкликав класичні токени в грудні 2025 року й обмежив гранульовані токени з правом запису девʼяноста днями, замінивши їх сесійною автентифікацією. Якщо ви публікуєте пакети, переходьте на trusted publishing через свій CI; практичний орієнтир — рекомендації OpenJS.
- Розділяйте доступи за призначенням. Токен, який деплоїть, не має бути токеном, який читає вашу базу, і жоден із них не має жити у профілі оболонки розробника. Це той самий принцип, що й реєстр доступів із матеріалу про те, чого насправді вимагають пункти клієнта про безпеку.
Питання до підрядника
Якщо сайт збирає й деплоїть хтось інший, чотири питання визначають вашу реальну експозицію. Це доречні питання, і компетентний виконавець матиме відповіді напоготові.
«Де виконується збірка?» Названий CI-сервіс — хороша відповідь. «На моїй машині» — чесна відповідь, яка означає, що ризик дорівнює гігієні одного ноутбука.
«Які доступи є на складальній машині?» Ви шукаєте короткий перелік, обмежений деплоєм, а не ноутбук із доступом до продакшн-бази й ключами ще пʼятьох клієнтів.
«Чи комітите ви lock-файл і чи переглядаєте оновлення залежностей?» Закомічений lock-файл, який рідко змінюється без перегляду, — це різниця між детермінованою збіркою й лотереєю.
«Що буде, якщо завтра якусь залежність визнають шкідливою?» Відповідь має включати ротацію доступів, перезбірку з відомого справного стану й перевірку того, куди могла дістати складальна машина. Якщо відповіді немає, це і є прогалина.
Якщо ви вважаєте, що вас зачепило
Швидкість важливіша за впевненість. Виходьте з припущення про компрометацію й дійте в такому порядку.
Змініть усі облікові дані, які були на ураженій машині або в ураженому конвеєрі: npm-токени, хмарні ключі, ключі деплою, паролі баз, ключі API до сторонніх сервісів. Ротація дешева й оборотна; розслідування до ротації не є ані першим, ані другим.
Далі зʼясуйте, куди ці доступи діставали. Ключ деплою, який пише лише в стейджинговий бакет, — це зовсім інший інцидент, ніж адміністративний ключ до продакшн-бази.
Перезберіть проєкт із чистого клону на чистій машині, а не «видаліть поганий пакет». Шкідливий код уже виконався; видалення пакета прибирає пакет, а не наслідки.
Нарешті шукайте сліди: нові репозиторії у вашій організації, нові ключі деплою, нових учасників, несподівані файли робочих процесів. Такі кампанії лишають артефакти, і саме за артефактами підтверджують масштаб. Це також момент, коли резервна копія з перевіреним відновленням перестає бути папером, — з причин, викладених у матеріалі про те, що перевірити до того, як воно знадобиться.
Той самий сценарій поза npm
npm — найгучніший приклад, бо це найбільший реєстр і той, який за замовчуванням виконує сторонній код уже під час встановлення. Але сама форма атаки — зламати одного підтримувача й успадкувати всіх, хто від нього залежить, — не є особливістю JavaScript. Для звичайного бізнесового сайту три суміжні випадки важливіші за черв’яка у конвеєрі збірки, бо вони дістаються продакшена напряму, а не через ноутбук розробника.
Плагіни WordPress. Плагін зі сотнею тисяч встановлень продають, успадковують або тихо передають іншим людям, і канал оновлень переходить разом із ним. Код, що приходить в автоматичному оновленні, має рівно ті самі права, що й код, який ви переглядали в день встановлення: повний доступ до сайту та його бази даних. Тому питання «хто публікує цей плагін тепер і чи це ті самі люди, які його написали?» варте того, щоб стояти в перевірці поруч із номером версії. Занедбані плагіни — повільніша версія тієї ж проблеми: нікому не потрібно бути зловмисником, щоб плагін без підтримки став входом усередину. Працює не довгий список, який ніхто не читав із моменту запуску, а короткий інвентар, який хтось справді веде; такий інвентар — одна з тих речей, для яких існує нормальна угода про супровід.
Розширення браузера. Той самий сценарій із перекупівлею стосується й розширень, і тут радіус ураження включає кожну адмін-сесію, відкриту в цьому браузері. Браузер розробника часто є найменш контрольованою машиною з доступом до вашого продакшена — і єдиним місцем, де для компромісу взагалі не потрібен крок збірки.
Усе, що завантажується під час збірки або відкриття сторінки й не є пакетом. Шрифти, набори іконок, фрагменти аналітики та скрипти з CDN, які підтягуються зі сторонньої URL-адреси, — це залежності без lock-файлу: файл за тією адресою може змінитися без жодної зміни номера версії, і ніщо у вашому процесі цього не помітить. Розміщення їх на власному сервері закриває одразу два питання — підміни та приватності.
Спільна риса — довіра, видана одного разу й ніколи не переглянута. Кожен із цих каналів колись хтось схвалив, і цей хтось на нього більше не дивиться. Тобто це проблема обслуговування, вдягнена в костюм безпеки.
Що це змінює в тому, як будують сайти
Два зсуви вже помітні, і обидва стосуються радше закупівлі, ніж коду.
Кількість залежностей тепер є витратою, а не нейтральним фактом. Фреймворк, який підтягує три сотні пакетів, щоб показати сайт-візитівку, несе ризик, якого простіший стек не має. Раніше цей аргумент був про вагу сторінки, тепер він про експозицію — міркування, яке стоїть поруч із тими, що в матеріалі про те, що ламається в поспіхом згенерованих сайтах, де залежності накопичуються швидше, ніж хтось їх переглядає.
І середовище збірки тепер є частиною результату роботи. Договір, який описує сайт, але нічого не каже про те, де він компілюється, з якими доступами й ким, пропустив саме ту частину, у яку цілять атаки цього року. Дописати ці три рядки під час підписання коштує нуль, а вбудувати їх під час інциденту майже неможливо.
Коротко
- Серпнева хвиля 2026 року була найбільшою, діставши
keyvі сотні повʼязаних пакетів за години через самопоширення. - Шкідливий код виконується під час встановлення, а не під час роботи застосунку, тож достатньо просто встановити залежність.
- Якщо у вашого сайту є крок збірки, ви в зоні дії — включно з багатьма сайтами на WordPress зі скомпільованими темами або кастомними блоками.
- Найцінніші заходи: одноразові середовища збірки, вимкнені install-скрипти з коротким білим списком, закомічені lock-файли, відкладені оновлення й відсутність довгоживучих публікаційних токенів.
- npm відкликав класичні токени в грудні 2025 року й обмежив гранульовані токени з правом запису девʼяноста днями; передбачена заміна — trusted publishing через CI.
- Якщо зачепило — спершу ротація, потім розслідування, далі чиста перезбірка й пошук репозиторіїв, ключів і учасників, яких ви не створювали.








