npm-пакети Red Hat Cloud Services скомпрометовано в атакі з отруєнням ланцюжка постачання

iconMetaEra
Поділитися
Share IconShare IconShare IconShare IconShare IconShare IconCopy
AI summary iconКороткий зміст

expand icon
Про безпековий інцидент повідомлено у кількох пакетах npm, що належать організації Red Hat Cloud Services, згідно з он-чейн новинами від MetaEra. Система MistEye виявила 96 шкідливих версій у 32 пакетах, з яких три були проаналізовані детально. Шкідливий код у пакетах, таких як @redhat-cloud-services/frontend-components-config@6.11.3, виконується під час встановлення через preinstall-хук. Цей шкідливий програмний код — варіант Shai-Hulud — містить функції крадіжки облікових даних та експлуатації CI/CD. Зловмисники використовували ROT/Цезаря, AES-GCM та B5-шифрування, щоб приховати завантаження, яке поширюється через npm та робочі процеси GitHub.

Контекст

Недавно система безпеки MistEye зафіксувала інформацію про аномальні версії кількох npm-пакетів, що належать організації Red Hat Cloud Services. У цій події було задіяно 32 npm-пакети та 96 версій від цієї організації. У цій статті ми глибоко проаналізували в офлайн-режимі три локальні зразки: ці зразки не є підробленими неймспейсами чи пакетами з опечатками, а є справжніми версіями пакетів зі скоупом @redhat-cloud-services; з джерельного коду зразків можна підтвердити, що у їх tarball було вставлено багатошаровий заплутаний зловмисний лоадер, який автоматично активується під час встановлення.

Після повного відновлення можна підтвердити: ці три зразки мають основні функції, що дозволяють читати пам’ять GitHub Actions Runner, збирати облікові дані з кількох хмар та локальних систем, виводити дані через GitHub API та використовувати dead-drop, ін'єкцію в GitHub workflow, саморозповсюдження через npm, зберігання стійкості через Claude Code / VS Code / systemd / LaunchAgent, протидію Harden-Runner / StepSecurity, а також виявлення EDR та інших засобів безпеки. З огляду на діапазон функцій, потенційно під загрозою перебувають розробницькі хости, CI/CD Runner, збірні контейнери, GitHub репозиторії, GitHub Actions workflow, ланцюжок публікації npm та облікові дані хмарного середовища. Реальний масштаб впливу потрібно підтвердити за допомогою логів встановлення, аудиту репозиторіїв та телеметрії з боку платформи.

З точки зору структури коду, шляхів поширення та комбінації здібностей цей шкідливий програмний код є варіантом Shai-Hulud.

MistEye відповідь

MistEye — це власна розробка SlowMist система виявлення загроз та динамічного моніторингу безпеки Web3, яка поєднує функції безпекового моніторингу та агрегації інформації, надаючи користувачам актуальні попередження про ризики та захист активів.

Після виявлення цієї атаки на ланцюжок постачання npm-пакетів Red Hat Cloud Services та пов’язаних з нею зловмисних зразків, система MistEye ініціювала високий рівень тривоги та провела системний аналіз змішаної структури, розшифровки завантаження, відновлення функцій та IOC цієї атаки.

(https://enterprise.misteye.io/threat-intelligence/SM-2026-378450)

Огляд ланцюжка атак

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

Зразки, охоплені цією перевіркою:

@redhat-cloud-services/frontend-components-config

Версія: 6.11.3

tgz SHA-256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060

@redhat-cloud-services/types

Версія: 3.6.1

tgz SHA-256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558

@redhat-cloud-services/rule-components

Версія: 4.7.2

tgz SHA-256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f

Три зразки мають однаковий вхід для атаки: у всіх файлі package.json присутній scripts.preinstall = "node index.js". Це означає, що при встановленні цих версій на хості розробника або в середовищі CI/CD файл index.js у кореневому каталозі автоматично виконується на етапі встановлення, без необхідності явного імпорту або запуску коду.

Три зразки мають спільний основний шкідливий навантаження, але різні зовнішні параметри обгортки. Іншими словами, три зразки використовують різні значення зсуву ROT/Caesar та ключі/AES-GCM iv/tag; це ускладнює пряме використання статичних ознак, заснованих на хеші зовнішньої обгортки, фіксованому ключі або фіксованому зсуві, між зразками. Однак хеш розшифрованого запускача середовища Bun та основного шкідливого навантаження повністю збігається: один — це допоміжний модуль для підготовки середовища Bun, інший — справжнє навантаження зі шкідливими функціями. У цій статті ми називатимемо їх відповідно «запускачем середовища Bun (назва змінної в коді _b)» та «основним шкідливим навантаженням (назва змінної в коді _p)».

Відновлена ланцюжок атаки виглядає так:

Технічний аналіз

1. Вхід: підміна сценаріїв npm-життєвого циклу

Всі три зразки запускають ланцюжок атаки через preinstall життєвий цикл у package.json:

"scripts": {

"preinstall": "node index.js"

}

preinstall виконується автоматично на етапі встановлення npm. Для звичайних фронтенд-компонентів, визначень типів або пакетів правил зазвичай не потрібно запускати великий JavaScript-файл у кореневому каталозі під час встановлення; це найбільш прямий сигнал про аномалію.

Докази на рівні зразка такі:

@redhat-cloud-services/frontend-components-config@6.11.3

  • main: lib/index.js
  • поле files: ["/lib", "/bin"]
  • Кореневий файл index.js SHA-256: 545a1838c66e1771f58d84a17b3e1841e5eeab91a73f4ccc59c9492450a6d9c0

@redhat-cloud-services/types@3.6.1

  • main: index.d.ts
  • Поле files: не встановлено
  • Кореневий файл index.js SHA-256: b86c5ae9e95bd841a595440faa3eb6317441e746f241ae8fd641ab59ed1d1966

@redhat-cloud-services/rule-components@4.7.2

  • main: index.js
  • Поле files: не встановлено
  • Кореневий файл index.js SHA-256: 1a30a9abe20bab121aaa75ed040565af14e6cdfb745609ee0e7b94a2d814fb9c

У цьому випадку поле files пакета frontend-components-config@6.11.3 вказує лише на "/lib" та "/bin", але в кореневій директорії tarball існує додатковий файл index.js, який викликається preinstall. Ця аномалія відноситься лише до цього зразка; types@3.6.1 та rule-components@4.7.2 не встановлюють поле files, тому цю аномалію не можна узагальнювати на всі зразки.

2. Перший рівень: масив цифр + ROT/Caesar заміна літер

Кореневий файл index.js трьох зразків — це надвеликий однорядковий JavaScript-файл з однаковою структурою; основа — обгортка try { eval(...) } catch (...)

Цей обгортка спочатку перетворює великий масив чисел на рядок за допомогою String.fromCharCode, потім виконує ROT/Caesar-зсув для латинських літер у рядку і нарешті передає розшифрований результат функції eval для виконання. Обробка винятків виводить лише префікс wrapper:, щоб зменшити помітність винятків при невдалих спробах встановлення.

Значення зовнішнього зміщення та Stage 2 hash для трьох зразків:

frontend-components-config@6.11.3

index.js розмір: 4 294 798 байт

ROT/Caesar shift: 10

Етап 2 SHA-256: b19c2fd48535c8c40aeb3e627ce92775f33ef9292611767bb1236c238e6f90cc

types@3.6.1

index.js розмір: 4 135 588 байт

ROT/Caesar shift: 4

Етап 2 SHA-256: 9c0425aa6e6d7792ac38d24f3e7245f42fcaa553ddfeb6bd97677017f10c3b75

rule-components@4.7.2

index.js розмір: 4 294 336 байт

ROT/Caesar shift: 11

Етап 2 SHA-256: d590bd375d95e4ac072b7ebc1fc4489bcaf5f20a939e92486267aa398bcf1e5d

3. Другий рівень: розшифрування Bun-загрузчика та основного завантаження за допомогою AES-128-GCM

Код етапу 2, розшифрований за допомогою ROT/Caesar, виконує розшифрування AES-128-GCM (Advanced Encryption Standard - Galois/Counter Mode) за допомогою Node.js crypto.createDecipheriv і встановлює маркер автентифікації за допомогою setAuthTag. Метою розшифрування є два наступні компоненти: бутстрапер середовища Bun та основний шкідливий навантаження.

При цьому загрузчик середовища Bun відповідає за виявлення, локалізацію або підготовку середовища виконання Bun, щоб подальший код міг виконуватися через Bun; основний шкідливий навантаження є основою ланцюжка атаки та містить основні шкідливі функції, такі як збір облікових даних, поширення через GitHub/npm, збереження стійкості, протидія захисту та розшифрування вбудованих ресурсів.

Три зразки були зашифровані різними ключами AES-128-GCM, початковими векторами та аутентифікаційними мітками для обох компонентів, але після розшифрування SHA-256 трьох бутстреперів середовища Bun становить ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6, а SHA-256 трьох основних шкідливих навантажень — 0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35. Це свідчить про те, що нападники змінювали зовнішні параметри упаковки в різних npm-пакетах, але повторно використовували той самий набір основних шкідливих компонентів.

Після розшифрування Stage 2 записує основний шкідливий навантаження до /tmp, виконує його через Bun, а потім видаляє тимчасові файли. Реальна логіка, відновлена з трьох зразків, виглядає так:

Отже, перевірений шаблон тимчасових файлів у трьох зразках:

/tmp/p.js

Розмір завантажувача середовища Bun становить 898 байт, три зразки мають повністю однакові хеші:

ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6

Оточення виконання Bun містить логіку, таку як child_process.execSync, fs.existsSync, fs.mkdtempSync, fs.chmodSync, os.platform(), os.arch(), getBunPath() тощо, для визначення або підготовки оточення виконання Bun. Іншими словами, етап 2 не припускає просто, що глобальний Bun вже встановлено в системі; у випадку, коли шлях до оточення виконання Bun відсутній, спочатку завантажується загрузчик оточення виконання Bun, а потім через getBunPath() викликається Bun для виконання основного шкідливого навантаження.

4. Третій рівень: таблиця рядків obfuscator.io

Основний шкідливий навантаження, що був розшифрований, не є читабельним текстом JavaScript, а продовжує бути заплутаним за допомогою стилю obfuscator.io з використанням таблиць рядків. Цей рівень збирає велику кількість рядків у масиви та відновлює їх за допомогою індексації та логіки ротації в час виконання, що перешкоджає аналітикам отримати доступ до ключових API, шляхів та імен конфігурацій, доки таблиця рядків не буде повністю відновлена.

5. Четвертий рівень: B5 кастомне шифрування рядків

Після розшифрування таблиці рядків obfuscator.io, у ядрі зловмисного завантаження зберігається додатковий шар власного шифрування рядків B5. Параметри підтверджено:

  • KDF: PBKDF2 (Функція производення ключа на основі паролю 2)
  • Хеш-функція: SHA-256
  • Кількість ітерацій: 200000
  • довжина ключа: 32 байти
  • Кількість раундів розшифрування: 3
  • пароль: ba2c6ddb3672bdd6a611e6850b4f700b52aed3dab2f1b3d5f8c839d4a157a709
  • salt: 5b26508dc0f1075a7c0b4d8aa464487e

Розшифрований результат такий:

У цьому випадку після розшифрування B5 видно кілька ключових рядків у відкритому вигляді. Варто зазначити, що деякі рядки спочатку розташовувалися в таблиці рядків obfuscator.io і стають безпосередньо доступними для grep лише після завершення обох кроків: «заміна таблиці рядків + розшифрування B5»:

6. Додатковий вбудований шар: AES-256-GCM + gzip

Всередині основного шкідливого навантаження містяться вбудовані ресурси, зашифровані за допомогою AES-256-GCM та стиснені за допомогою gzip. Логіка розпакування використовує:

Ключові вбудовані ресурси, що були розшифровані, поділено на три категорії за функцією:

Читання пам’яті між платформами:

Цей тип ресурсів використовується для читання пам’яті запущених процесів. Ключі та токени у звичайних файлах можна виявити шляхом пошуку файлів, але CI/CD Runner або інструменти розробки зберігають деякі конфіденційні значення у пам’яті під час виконання. Зловмисники впроваджують сценарії читання пам’яті для трьох платформ — Linux, Windows та macOS — з метою отримання цих тимчасових секретів з пам’яті процесів на різних системах.

Підтримка конфігурації:

Ці ресурси використовуються для «залишення бекдорів». Іншими словами, навіть після завершення початкового процесу встановлення npm, зловмисники бажають, щоб шкідливий код знову запускався, коли розробник пізніше відкриє проект, запустить редактор, увійде в сеанс Claude Code або після перезавантаження системи. Тому ці ресурси націлені на конфігурацію проекту та механізми автозапуску на рівні користувача: конфігурація проекту є більш прихованою, а системні служби краще підходять для довготривалого виконання.

C2 та поширення:

Ці вбудовані ресурси використовуються для подальшого контролю ланцюжків та перенесення секретів репозиторію. Після розшифровки YZ — це монітор пошуку комітів GitHub, який періодично шукає повідомлення комітів у форматі firedalazer ., перевіряє підпис і завантажує та виконує віддалений Python-код; zZ після розшифровки — це шаблон GitHub Actions workflow під назвою Run Copilot, який записує ${{ toJSON(secrets) }} у файл format-results.txt та завантажує його як артефакт. Перший надає ланцюжок отримання/виконання завдань, другий — шаблон для перенесення секретів репозиторію через артефакти GitHub Actions; фактична ін’єкція workflow, очікування виконання та завантаження артефактів виконуються за допомогою супутньої логіки GitHub API, вбудованої в основний завантажувач.

Аналіз основних зловмисних завантажень

Після завершення багатошарової дезофускації зразок врешті-решт вивантажує та виконує основний шкідливий навантаження. Усі наступні аналізи проводяться щодо модуля основного шкідливого навантаження, розбиваючи його на п’ять етапів: отримання даних, виведення, поширення, стійкість та протидія.

Читання пам’яті GitHub Actions Runner:

Зразок містить сценарії читання пам’яті для платформ Linux, Windows та macOS, забезпечуючи крос-платформну здатність дампу. У реалізації для Linux збирання пам’яті виконується шляхом читання /proc//maps та /proc//mem цільового процесу:

Активна логіка запуску зловмисного навантаження спрямована на Linux-раннер GitHub Actions: коли GITHUB_ACTIONS === "true" і RUNNER_OS === "Linux", код шукає процес Runner.Worker, здійснює дамп пам’яті, а потім витягує приховані секрети у форматі "":{"value":"","isSecret":true}. У трьох зразках підтверджено, що активний збір фокусується на Linux-раннері, але сценарії для всіх трьох платформ вже вбудовані.

2. Багатохмарність та збір локальних облікових даних розробників:

Основний шкідливий навантаження містить систематизований модуль збору облікових даних, який охоплює хмарних провайдерів, CI-середовища, локальні налаштування розробників, GitHub CLI, менеджери паролів та файли гаманців.

Мети збирання облікових даних хмарного провайдера:

Модуль AWS також містить логіку, пов’язану з ECS/IMDS (Instance Metadata Service)/STS WebIdentity.

Збір локальних облікових даних розробника охоплює такі цілі:

Логіка менеджера паролів реалізована у вигляді масиву runCommand(command, args) у вихідному коді, а не шляхом конкатенації рядків оболонки.

Модуль збору облікових даних охоплює широкий спектр цілей — від хмарних платформ до локальних розробників; зібрані конфіденційні дані передаються за допомогою наступних механізмів.

3. GitHub API та dead-drop:

Основний шкідливий навантаження використовує GitHub API як основний канал витоку даних. Запити маскуються під User-Agent python-requests/2.31.0; після перевірки токена за x-oauth-scopes (який повинен містити repo, public_repo або workflow) виконується операція витоку: створюється репозиторій (опис фіксований як Miasma: The Spreading Blight), а вкрадені дані, закодовані в base64, записуються за допомогою PUT /repos///contents/results/.

Крім того, завантаження реалізує механізм dead-drop на основі пошуку комітів GitHub, отримуючи команди C2 шляхом пошуку маркера "thebeautifulmarchoftime" (або "thebeautifulsnadsoftime"):

let result = await X9("thebeautifulmarchoftime ", xZ);

Вбудований ресурс YZ.bin є самостійним монітором комітів GitHub, який з інтервалом 3600 секунд опитує пошук коміт-повідомлень у форматі firedalazer . Після успішної перевірки підпису завантажує та виконує віддалений Python-код. Це утворює окрему ланку подальшого керування, незалежну від основного каналу передачі.

У вихідному коді також міститься конфігураційний об’єкт HTTP POST-відправника, спрямований на ендпоінти api.anthropic.com та v1/api. Поле noop цього конфігураційного об’єкта встановлено на true, що означає, що без зовнішніх змін цей відправник не здійснюватиме реальних мережевих запитів. Тому статичний аналіз може лише підтвердити наявність цієї структури коду, але не може довести наявність активної експлуатації Anthropic API.

4. Інфекція сховища GitHub та робочого процесу:

Основний шкідливий навантаження може взаємодіяти з об’єктами git репозиторію за допомогою API GitHub REST / GraphQL:

Зловживальний виклик, створений під ім’ям релізу, запитує дозвіл id-token: write та використовує шлях OIDC (OpenID Connect) для отримання npm-токена для публікації. Змінні оточення та інтерфейс шляху OIDC — ACTIONS_ID_TOKEN_REQUEST_TOKEN, ACTIONS_ID_TOKEN_REQUEST_URL, аудиторія встановлена як npm:registry.npmjs.org. На рівні вихідного коду підтверджено, що завантаження має здатність ін’єктувати workflow у репозиторій GitHub та використовувати OIDC / npm trusted publishing для отримання прав на публікацію.

Крім вищезазначеного способу ін'єкції workflow через git refs, завантаження також містить більш приховану механізм перенесення секретів: workflow GitHub Actions, що маскується під Run Copilot, записує ${{ toJSON(secrets) }} у format-results.txt та завантажує артефакт. У порівнянні з прямим записом секретів у вміст репозиторію, цей підхід більше спрямований на перенесення даних через результати виконання workflow, і звичайний аналіз коду через diff може не виявити кінцевий виведений вміст секретів.

5. Запустіть робочий процес Copilot через artifact для перенесення секретів:

Вбудований ресурс zZ.bin — це GitHub Actions workflow, який маскується під Copilot, і записує ${{ toJSON(secrets) }} у format-results.txt, а потім завантажує його як артефакт.

Пов’язані поведінки GitHub API включають: створення/оновлення тимчасової гілки → запис blob робочого процесу → очікування виконання робочого процесу → завантаження артефакту zip → читання format-results.txt → видалення виконання робочого процесу та тимчасової гілки. Відповідні ключові слова для пошуку: Run Copilot, VARIABLE_STORE, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml.

6. npm саморозповсюдження:

Основний шкідливий навантаження має дві незалежні маршрути публікації/розповсюдження через npm.

Шлях до токена npm: завантаження через GET /-/npm/v1/tokens перераховує токени поточного користувача npm, фільтрує токени з bypass_2fa === true та правами на запис у пакет, використовуючи ці токени для автоматизованого публікування. bypass_2fa — це поле метаданих токена, а не параметр publish тіла.

Шлях GitHub Actions OIDC: читається змінні середовища ACTIONS_ID_TOKEN_REQUEST_TOKEN та ACTIONS_ID_TOKEN_REQUEST_URL, запитується OIDC-токен з аудиторією npm:registry.npmjs.org, отримується права на публікацію через інтерфейс обміну OIDC-токеном npm.

Операції з забрудненням tarball: розпакувати → записати шкідливий index.js → змінити package.json:

Тут розрізняються два типи входів: для трьох локальних завантажених зразків використовується preinstall: "node index.js" — у цьому випадку середовище встановлення не потребує попередньої встановленої Bun, і використання Node.js як початкового входу є більш прихованим; під час саморозповсюдження та забруднення інших пакунків записується preinstall: "bun run index.js" і додається залежність bun — оскільки подальша логіка основного шкідливого навантаження залежить від API, наданих середовищем виконання Bun (наприклад, Bun.gunzipSync і Bun.file), у сценаріях саморозповсюдження необхідно переконатися, що цільове середовище має Bun.

7. Механізм персистентності:

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

Claude Code SessionStart hook: Вбудований ресурс S8.bin записує SessionStart hook у .claude/settings.json, щоб кожного разу, коли запускається сесія Claude Code, автоматично виконувався node .claude/setup.mjs. Зловмисний навантаження також записується у .claude/setup.mjs і .claude/index.js (шлях формується як ".claude/" + M0, де M0 = "index.js").

Завдання folderOpen у VS Code: вбудований ресурс EZ.bin записує завдання folderOpen у файл .vscode/tasks.json і автоматично виконує той самий сценарій при відкритті папки проекту, який був заражений. Також записується файл .vscode/setup.mjs.

kitty-monitor (systemd / LaunchAgent): вбудований ресурс RZ.bin встановлює автозавантажувану службу, файли розподілені по /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service (Linux) та ~/Library/LaunchAgents/com.user.kitty-monitor.plist (macOS). Зловмисний навантаження створює директорію /tmp/kitty-, записує YZ.bin (монітор GitHub commit) у cat.py, а потім встановлює його через RZ.bin.

gh-token-monitor (systemd / LaunchAgent): Вбудований ресурс jZ.bin для встановлення служби моніторингу GitHub-токенів; файли розташовані у /.local/bin/gh-token-monitor.sh, /.config/gh-token-monitor/ та відповідних шляхах systemd / LaunchAgent. Монітор перевіряє, чи повертає GitHub-токен код стану 40x, а також чи є незвичними метадані npm-пакету @cap-js/openapi@1.4.1, і при спрацьовуванні виконує обробник:

Це означає, що коли monitor виявляє, що GitHub API повертає код стану 40x, наприклад, коли токен було скасовано, він став недійсним або його права мають ненормальний стан, зловмисний сценарій виконує переданий обробник. У трьох зразках, відновлених у цій статті, обробник має вигляд: rm -rf ~/; rm -rf ~/Documents. Під час реагування не слід скасовувати токен безпосередньо на хості, де може все ще виконується payload — спочатку слід ізольовувати хост, очищати засоби персистентності та процеси, що виконуються, а потім змінювати облікові дані з чистого середовища.

8. Harden-Runner / StepSecurity:

Основний шкідливий навантаження містить вбудовану логіку виявлення та знищення StepSecurity Harden-Runner, обходячи захист CI/CD за допомогою таких кроків:

  1. Перевірити доступність сокета Docker /var/run/docker.sock;
  2. Перелік контейнерів Docker, що відповідають ключовим словам harden-runner / stepsecurity у назві або образі;
  3. Зупиніть відповідний контейнер за допомогою POST /containers//kill;
  4. Створіть привілейований контейнер Alpine, перепишіть sudoers як runner ALL=(ALL) NOPASSWD:ALL;
  5. Записати недійсні розшифровки доменів StepSecurity у /etc/hosts;
  6. Перезаписати /etc/resolv.conf на 8.8.8.8 та 1.1.1.1.

Ця протистояльна логіка вказує, що зразок був спеціально адаптований для середовищ CI/CD, захищених StepSecurity.

9. EDR / Виявлення безпечних продуктів, оцінка середовища та уникнення:

Основний шкідливий навантаження виявляє імена процесів та шляхи встановлення різних продуктів EDR (Endpoint Detection and Response) / безпеки:

Навантаження також містить логіку обходу регіонів: виявлення змінних середовища LC_ALL, LC_MESSAGES, LANGUAGE, LANG; після перетворення їх у нижній регістр, якщо вони починаються з ru, виконання пропускається. Підтримка виявлення CI-середовищ: GitHub Actions, GitLab CI, Travis CI, CircleCI, Jenkins, AWS CodeBuild, Buildkite, AppVeyor, Bitbucket, Drone, TeamCity, Cirrus CI тощо. Позначки стану, що використовуються під час виконання: tmp.0987654321.lock, __IS_DAEMON (позначка від’єднаного дочірнього процесу демона), SKIP_DOMAIN (пропустити шлях відправника домену), /tmp/kitty-*, cat.py та /var/tmp/.gh_update_state.

Аналіз впливу

З точки зору здатності до вихідного коду, вплив цих трьох зразків не обмежується одноразовим виконанням на етапі встановлення через npm. Їх реальний ризик можна поділити на чотири рівні:

На рівні хоста розробника. Зразки збирають змінні середовища, .npmrc, .pypirc, SSH-ключі, конфігурацію Docker, .env, токен GitHub CLI, дані менеджера паролів та файли гаманців, а також забезпечують подальшу здатність до запуску через Claude Code, VS Code, systemd user service або macOS LaunchAgent.

На рівні CI/CD Runner. Зразок виявляє Linux runner GitHub Actions, читає пам’ять процесу Runner.Worker та вилучає приховані секрети; одночасно має механізми протидії StepSecurity Harden-Runner, намагаючись зруйнувати або обійти компоненти захисту CI/CD.

Рівень організації та сховища GitHub. Зразки можуть використовувати GitHub API для створення сховищ, запису в contents/results/, маніпулювання git refs/blobs/trees/commits, введення зловмисного workflow та перенесення секретів за допомогою Run Copilot workflow + artifact.

На рівні поширення в екосистемі npm. Зразки можуть бути відібрані з правами на запис у пакет із bypass_2fa === true, а також можуть використовувати шлях GitHub Actions OIDC / npm trusted publishing для отримання прав на публікацію; після цього завантажується цільовий tarball, вставляється шкідливий загрузчик, змінюється preinstall, додається залежність від Bun, підвищується версія патчу та публікується, що формує ланцюжок саморозповсюдження в npm.

Підсумок

Докази вихідного коду трьох зразків показують, що цей шкідливий пакет не є просто сценарієм крадіжки даних під час встановлення, а є комбінацією багатоетапного завантажувача та повного вбудованого коду: зовнішній шар випадково змінюється для кожного пакету, а середовище запуску Bun та основний шкідливий навантаження залишаються незмінними; основний вбудований код охоплює збирання облікових даних, витягування CI-секретів, поширення через GitHub/npm, забезпечення стійкості та протидію захисту.

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

Багатошарова ланцюжкова дезфіксація. Зловмисний навантаження проходить через п’ять рівнів упаковки: числовий масив + ROT-заміна літер, AES-128-GCM шифрування, обфускація через obfuscator.io, власний строковий шифр B5, та вкладений шар AES-256-GCM + gzip. Ключі чи параметри кожного рівня можуть незалежно змінюватися між пакетами, що ускладнює масове виявлення на основі статичних ознак.

Повний організаційний рівень здатності до атак. Цей імплант має здатність читати пам’ять GitHub Actions Runner, збирати облікові дані з багатьох хмар та локальних середовищ, вивозити дані через GitHub API та dead-drop, заражати репозиторії та workflow GitHub, саморозповсюджуватися через npm, забезпечувати стійкість та протидію захисту. Згідно зі структурою вихідного коду, він вже має шляхи для поширення від однієї точки встановлення до репозиторіїв, CI/CD та ланцюжків публікації npm; реальний масштаб поширення потрібно підтвердити за допомогою журналів встановлення, аудиту репозиторіїв та телеметрії платформи.

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

Рекомендації щодо обробки

  1. Виявіть та видаліть шкідливі версії з залежностей проекту, файлів lock, кешу приватних реєстрів та кешу збирання.
  2. Перевірте журнал встановлення на наявність preinstall, node index.js, bun run, /tmp/p*.js, tmp.0987654321.lock.
  3. Не відкликайте токен безпосередньо на жертві, яка ще може виконувати payload. Рекомендується спочатку ізольовувати заражений хост, очистити запущені процеси та елементи автозавантаження, а потім змінити токени, пов’язані з GitHub, npm, хмарними обліковими даними, Kubernetes, Vault, SSH, реєстром Docker та менеджерами паролів, з чистого середовища.
  4. Перевірте останні гілки, коміти, робочі процеси, артефакти та нові репозиторії на GitHub, зосереджуючись на ключових словах Run Copilot, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml, OIDC_PACKAGES.
  5. Перевірте, чи були додані або змінені файли у каталозі проекту: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, .vscode/setup.mjs.
  6. Перевірте файли користувацької персистентності: /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service, ~/Library/LaunchAgents/com.user.kitty-monitor.plist, файли, пов’язані з gh-token-monitor.
  7. Перевірте історію npm publish, щоб переконатися, чи не було неавторизованих патч-версій; одночасно проведіть аудит метаданих npm token, зосереджуючись на token, які дозволяють обійти 2FA (Two-Factor Authentication) і мають права на запис пакетів.
  8. Провести аудит цілісності нижчих продуктів, створених у забрудненому середовищі.

IOC

Шкідливий файл

ім’я файлу: redhat-cloud-services-frontend-components-config-6.11.3.tgz MD5: 633ad8849a59e2bfb7a0fe589e816a07 SHA1: 675294612f455fe6a9acb195f0cbe3687d8e2e34 SHA256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060

ім’я файлу: redhat-cloud-services-types-3.6.1.tgz MD5: 9e6c5af01438b52c9a411686c1f1b8ff SHA1: 88d098c8d96e9ae17550e9798c3b62c420464b8c SHA256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558

ім’я файлу: redhat-cloud-services-rule-components-4.7.2.tgz MD5: f1ffdbf5e639899f26a6ebab2eec408d SHA1: f3c5c21274045ae02fef11e931de6dcf8462a067 SHA256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f

SHA256

ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6

0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35

Зловживання залежністю

npm:@redhat-cloud-services/topological-inventory-client@3.0.10

npm:@redhat-cloud-services/topological-inventory-client@3.0.11

npm:@redhat-cloud-services/topological-inventory-client@3.0.13

npm:@redhat-cloud-services/compliance-client@4.0.3

npm:@redhat-cloud-services/compliance-client@4.0.4

npm:@redhat-cloud-services/compliance-client@4.0.6

npm:@redhat-cloud-services/rbac-client@9.0.3

npm:@redhat-cloud-services/rbac-client@9.0.4

npm:@redhat-cloud-services/rbac-client@9.0.6

npm:@redhat-cloud-services/insights-client@4.0.4

npm:@redhat-cloud-services/insights-client@4.0.5

npm:@redhat-cloud-services/insights-client@4.0.7

npm:@redhat-cloud-services/frontend-components@7.7.2

npm:@redhat-cloud-services/frontend-components@7.7.3

npm:@redhat-cloud-services/frontend-components@7.7.5

npm:@redhat-cloud-services/frontend-components-utilities@7.4.1

npm:@redhat-cloud-services/frontend-components-utilities@7.4.2

npm:@redhat-cloud-services/frontend-components-utilities@7.4.4

npm:@redhat-cloud-services/remediations-client@4.0.4

npm:@redhat-cloud-services/remediations-client@4.0.5

npm:@redhat-cloud-services/remediations-client@4.0.7

npm:@redhat-cloud-services/frontend-components-notifications@6.9.2

npm:@redhat-cloud-services/frontend-components-notifications@6.9.3

npm:@redhat-cloud-services/frontend-components-notifications@6.9.5

npm:@redhat-cloud-services/patch-client@4.0.4

npm:@redhat-cloud-services/patch-client@4.0.5

npm:@redhat-cloud-services/patch-client@4.0.7

npm:@redhat-cloud-services/host-inventory-client@5.0.3

npm:@redhat-cloud-services/host-inventory-client@5.0.4

npm:@redhat-cloud-services/host-inventory-client@5.0.6

npm:@redhat-cloud-services/rule-components@4.7.2

npm:@redhat-cloud-services/rule-components@4.7.3

npm:@redhat-cloud-services/rule-components@4.7.5

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.2

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.4

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.6

npm:@redhat-cloud-services/notifications-client@6.1.4

npm:@redhat-cloud-services/notifications-client@6.1.5

npm:@redhat-cloud-services/notifications-client@6.1.7

npm:@redhat-cloud-services/sources-client@3.0.10

npm:@redhat-cloud-services/sources-client@3.0.11

npm:@redhat-cloud-services/sources-client@3.0.13

npm:@redhat-cloud-services/integrations-client@6.0.4

npm:@redhat-cloud-services/integrations-client@6.0.5

npm:@redhat-cloud-services/integrations-client@6.0.7

npm:@redhat-cloud-services/frontend-components-config@6.11.3

npm:@redhat-cloud-services/frontend-components-config@6.11.4

npm:@redhat-cloud-services/frontend-components-config@6.11.6

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.2

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.3

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.5

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.1

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.2

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.4

npm:@redhat-cloud-services/frontend-components-remediations@4.9.2

npm:@redhat-cloud-services/frontend-components-remediations@4.9.3

npm:@redhat-cloud-services/frontend-components-remediations@4.9.5

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.1

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.2

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.4

npm:@redhat-cloud-services/javascript-clients-shared@2.0.8

npm:@redhat-cloud-services/javascript-clients-shared@2.0.9

npm:@redhat-cloud-services/javascript-clients-shared@2.0.11

npm:@redhat-cloud-services/quickstarts-client@4.0.11

npm:@redhat-cloud-services/quickstarts-client@4.0.12

npm:@redhat-cloud-services/quickstarts-client@4.0.14

npm:@redhat-cloud-services/config-manager-client@5.0.4

npm:@redhat-cloud-services/config-manager-client@5.0.5

npm:@redhat-cloud-services/config-manager-client@5.0.7

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.1

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.2

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.4

npm:@redhat-cloud-services/entitlements-client@4.0.11

npm:@redhat-cloud-services/entitlements-client@4.0.12

npm:@redhat-cloud-services/entitlements-client@4.0.14

npm:@redhat-cloud-services/tsc-transform-imports@1.2.2

npm:@redhat-cloud-services/tsc-transform-imports@1.2.4

npm:@redhat-cloud-services/tsc-transform-imports@1.2.6

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.1

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.2

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.4

npm:@redhat-cloud-services/frontend-components-testing@1.2.1

npm:@redhat-cloud-services/frontend-components-testing@1.2.2

npm:@redhat-cloud-services/frontend-components-testing@1.2.4

npm:@redhat-cloud-services/types@3.6.1

npm:@redhat-cloud-services/types@3.6.2

npm:@redhat-cloud-services/types@3.6.4

npm:@redhat-cloud-services/chrome@2.3.1

npm:@redhat-cloud-services/chrome@2.3.2

npm:@redhat-cloud-services/chrome@2.3.4

npm:@redhat-cloud-services/frontend-components-translations@4.4.1

npm:@redhat-cloud-services/frontend-components-translations@4.4.2

npm:@redhat-cloud-services/frontend-components-translations@4.4.4

npm:@redhat-cloud-services/vulnerabilities-client@2.1.8

npm:@redhat-cloud-services/vulnerabilities-client@2.1.9

npm:@redhat-cloud-services/vulnerabilities-client@2.1.11

Відмова від відповідальності: Інформація на цій сторінці може бути отримана від третіх осіб і не обов'язково відображає погляди або думки KuCoin. Цей контент надається лише для загального інформування, без будь-яких запевнень або гарантій, а також не може розглядатися як фінансова або інвестиційна порада. KuCoin не несе відповідальності за будь-які помилки або упущення, а також за будь-які результати, отримані в результаті використання цієї інформації. Інвестиції в цифрові активи можуть бути ризикованими. Будь ласка, ретельно оцініть ризики продукту та свою толерантність до ризику, виходячи з ваших власних фінансових обставин. Для отримання додаткової інформації, будь ласка, зверніться до наших Умов використання та Розкриття інформації про ризики.