Обновление Dependabot опубликовало "червя". 22 пакета.
Бот открывает запрос на слияние.
Бот открывает запрос на слияние. Человек принимает его через 24 минуты. Через 95 минут "червь" опубликовал 110 вредоносных версий 22 пакетов npm под его именем, используя токен, найденный в его CI.
Читать письменное издание (на английском) ↗
Что освещается в этом видео
- Бот, человек, червь
- Как это произошло, почему npm это допустил, кто виноват
- Хронология: отравленный кэш
- 21:48 — обновление Dependabot
- Почему это работает
Переведенная стенограмма
Переведено с оригинального английского повествования. Доступные аудио и субтитры контролируются YouTube.
Бот, человек, червь
0:00 Бот открывает запрос на слияние; человек принимает его двадцать четыре минуты спустя. Девяносто пять минут спустя "червь" опубликовал сто десять версий его пакетов, как он. В отчете TanStack о происшествии есть временные метки от upstream, а у downstream-сопровождающего есть остальное, а Hacker News дает этому тысячу сто баллов и имя: Mini Shai-Hulud. Как это происходит, почему npm это допускает, кто виноват.
Как это произошло, почему npm это допустил, кто виноват
0:21 Это The Daily Diff, постмортем. 11 мая, утро. Переименованный форк открывает запрос на слияние против TanStack Router. Он закрывается в течение часа, но рабочий процесс бенчмарка уже запустил свой код и
Хронология: отравленный кэш
0:33 сохранил отравленный кэш под ключом, который будет использовать рабочий процесс выпуска. Девятнадцать-двадцать. Легитимное слияние запускает выпуск. Кэш возвращается, бинарный файл считывает память раннера, извлекает токен публикации и отправляет восемьдесят четыре версии по сорока двум пакетам с действительным происхождением. Тесты не пройдены. Он все равно публикует. Девятнадцать сорок шесть, исследователь StepSecurity подает сообщение о проблеме; к девяти UTC все устарело и выпущено предупреждение.
0:55 Устаревшее не значит исчезнувшее: npm отказывается отменять публикацию чего-либо с зависимостями, поэтому оно остается устанавливаемым часами. Двадцать один сорок восемь. В девятизвездочном проекте данных об авиации, Dependabot открывает свой обычный запрос на слияние: обновить группу dev-dependencies, тринадцать обновлений. Два из них — отравленные версии TanStack. Двадцать два-двенадцать: принято. Рабочий процесс публикации запускает npm C-I с токеном в
21:48 — обновление Dependabot
1:15 области видимости; скрипт подготовки считывает его, и в двадцать два-семнадцать "червь" публикует как он. Пять версий каждого пакета, до которого добирается токен, даже старый сторонний проект: один классический токен для всего. Сто десять версий за девяносто пять минут. Он узнает об этом по электронной почте, после полуночи. Почему это работает. Первое: npm install по умолчанию запускает скрипты жизненного цикла незнакомых людей, и скрипт подготовки git-зависимости учитывается.
1:39 Второе: "червь" хочет одного: токен, который публикует без второго фактора. Затем он запрашивает у реестра, что еще принадлежит этому сопровождающему, и переиздает все это с самим собой внутри. Третье: ничто в цепочке не является человеком.
Почему это работает
1:51 Бот предлагает, конвейер устанавливает, и "червь" возвращает услугу: его ветки-тайники названы dependabot slash github-actions slash fremen. git blame. Модель установки npm, пятьдесят пять процентов: скрипты запускаются при установке, устаревшее остается устанавливаемым, существуют токены обхода двухфакторной аутентификации. CI TanStack, двадцать пять: непроверенный рабочий процесс цели pull request, запускающий код форка с правом записи в кэш. Привычка обновлять, пятнадцать: тринадцать обновлений, объединенных за двадцать четыре минуты, токен в комнате.
2:17 Dependabot, пять: настолько доверенный, что "червь" носит его униформу.
git blame
2:20 Радиус поражения: сорок два пакета TanStack. Двадцать два downstream, из проекта с девятью звездами. Более ста шестидесяти в экосистеме, как только "червь" достигает Mistral. Каждая upstream-версия имела действительную подпись: создана официальным конвейером. Верно. Вердикт, постмортем: SHIP IT. Оба сопровождающих публикуют постмортемы с временными метками в течение дня; в течение трех, downstream-конвейер устанавливается с ignore-scripts, разделяет сборку от публикации и отбрасывает долгоживущий токен.
Радиус поражения
2:47 Настройки npm по умолчанию не изменились. Понедельник: ignore-scripts при установке, и токен публикации вне задачи, которая его запускает. Пришлите мне инцидент, о котором вам до сих пор не разрешено говорить, в комментариях или на thedailydiff.dev. И это The Daily Diff на сегодня.
Вердикт
3:00 Я Нико из Axrisi. Объединяйте ответственно.
Источники
- TanStack postmortem (Tanner Linsley, May 11, refined May 15)tanstack.com
- TanStack "Hardening TanStack After the npm Compromise" (May 12)tanstack.com
- TanStack/router#7383 — the StepSecurity detection issuegithub.com
- Downstream incident post, @squawk/* (May 12)github.com
- Downstream hardening post (May 14)github.com
- The Dependabot PR #246 (opened 21:48 UTC, merged 22:12)github.com
- @tan_stack advisory post, 21:19 UTCx.com
- StepSecurity — worm internals, bypass_2fa search, Dependabot-style branch nameswww.stepsecurity.io
- Socketsocket.dev
- Aikido — "over 160 packages, including Mistral"www.aikido.dev
- Hacker News (1,097 points)news.ycombinator.com



