Tinycolor supply chain attack post-mortem
Атака на поставки @ctrl/tinycolor: разбор инцидента
Злоумышленник добавил вредоносный workflow в GitHub Actions общего репозитория и похитил npm-токен с правами публикации. С помощью этого токена были опубликованы вредоносные версии 20 пакетов, включая @ctrl/tinycolor.
Мой аккаунт GitHub и репозиторий @ctrl/tinycolor не были скомпрометированы напрямую. Не использовался фишинг, на моём компьютере не устанавливались вредоносные пакеты. GitHub и npm оперативно отреагировали, удалив зловредные версии. Я выпустил чистые версии пакетов для очистки кэшей.
Как это произошло
Раньше я участвовал в проекте angulartics2 — общем репозитории, где у нескольких человек были права администратора. Там остался секрет GitHub Actions — npm-токен с широкими правами на публикацию.
Злоумышленник принудительно отправил ветку Shai-Hulud в angulartics2 с вредоносным workflow. Workflow запустился сразу после отправки (без проверки, так как у collaborator были права администратора) и украл npm-токен. С помощью украденного токена атакующий опубликовал вредоносные версии 20 пакетов.
Планы на будущее
Сейчас я использую semantic-release с GitHub Actions для публикации. Моя цель — перейти на Trusted Publishing (OIDC) в npm, чтобы полностью отказаться от статических токенов. Однако интеграция с semantic-release ещё в разработке.
Для небольших пакетов я продолжу использовать semantic-release, но с ужесточённым контролем: никаких новых участников, отдельные npm-токены с правами только на публикацию конкретного пакета.
Я планирую и дальше использовать pnpm, который блокирует неавторизованные postinstall-скрипты, и изучу новую настройку minimumReleaseAge.
Пожелания к системе публикации
В идеале хотелось бы иметь в npm единый переключатель для принудительного использования Trusted Publishing (OIDC) для всех моих пакетов. Такой же переключатель блокировал бы любые релизы без provenance, обеспечивая безопасность на уровне аккаунта. Также хотелось бы иметь встроенную поддержку semantic-release с OIDC и provenance, чтобы статические токены больше не требовались.
Кроме того, было бы удобно иметь безопасный вариант публикации с подтверждением человека прямо в интерфейсе GitHub: защищённый workflow_dispatch, использующий 2FA GitHub для удовлетворения требованиям двухфакторной аутентификации без необходимости публиковать со своего компьютера.
Комментарии (67)
- Предлагается использовать ручные релизы и многоэтапные проверки для публикации пакетов вместо полной автоматизации CI/CD.
- Обсуждаются недостатки долгоживущих токенов и предлагается использовать Trusted Publishing с короткоживущими токенами или OIDC.
- Поднимается вопрос о необходимости встроенной MFA (двухфакторной аутентификации) для подтверждения публикации в CI-системах.
- Предлагается разделить процесс на загрузку пакета и его публикацию для пользователей, чтобы повысить контроль.
- Обсуждается идея использования подписей нескольких авторов или проверки подписей коммитов для обеспечения безопасности.
- Отмечается сложность настройки безопасных машинно-машинных потоков (OIDC) и необходимость более простых решений.
- Упоминается, что многие разработчики игнорируют вопросы безопасности до момента взлома и необходимы системные изменения.
Shai-Hulud malware attack: Tinycolor and over 40 NPM packages compromised 🔥 Горячее 💬 Длинная дискуссия
Компрометация пакетов ctrl/tinycolor и 40+ других в NPM
Популярный пакет @ctrl/tinycolor с более чем 2 млн загрузок в неделю был скомпрометирован вместе с 40+ другими пакетами в результате сложной атаки на цепочку поставок. Вредоносное ПО самораспространяется по пакетам maintainer'ов, собирает учетные данные AWS/GCP/Azure с помощью TruffleHog и создает бэкдоры через GitHub Actions.
Технический анализ
Атака реализуется через многоступенчатую цепочку, использующую Node.js process.env для доступа к учетным данным. Основной элемент — файл bundle.js (~3.6 МБ), который выполняется асинхронно во время npm install.
Механизм самораспространения
Вредоносное ПО через функцию NpmModule.updatePackage запрашивает API реестра NPM для получения до 20 пакетов maintainer'а и принудительно публикует обновления, создавая каскадный эффект компрометации.
Сбор учетных данных
Используются инструменты вроде TruffleHog для сканирования файловой системы на наличие секретов. Целевые учетные данные включают:
- Токены доступа GitHub
- Ключи доступа AWS
- Учетные данные Google Cloud Platform
Комментарии (962)
- Пользователи выражают обеспокоенность невозможностью аудита всех зависимостей и их уязвимостью к атакам в npm.
- Критикуется архитектура npm, в частности выполнение postinstall-скриптов по умолчанию, в отличие от других менеджеров пакетов.
- Предлагаются решения: игнорирование скриптов в настройках, песочница (bubblewrap), использование подписей кода и каррированных пакетов.
- Указывается на системную проблему экосистемы JS: огромное количество мелких зависимостей и отсутствие сильной стандартной библиотеки.
- Обсуждается масштаб атаки (180+ пакетов) и её возможная связь с государственными акторами.
- Поднимается вопрос уязвимости других экосистем (PyPI) и необходимости обязательной 2FA и подписи артефактов.
- Высказываются радикальные предложения по замене npm или созданию безопасного форка/дистрибутива пакетов.