В мире разработки программного обеспечения произошёл инцидент, который затронул миллионы разработчиков по всему миру. Группа исследователей из OpenSourceMalware обнаружила признаки масштабного захвата учётной записи мейнтейнера в реестре npm (основном хранилище пакетов для платформы Node.js). Жертвой атаки стал аккаунт atool, под управлением которого находится 547 пакетов, в том числе вся линейка библиотек визуализации данных AntV, разрабатываемая под эгидой Alibaba.
Описание
Злоумышленники действовали быстро и методично. В течение одного дня они опубликовали новые версии сразу 315 пакетов, что в общей сложности дало 633 артефакта (каждый артефакт - это конкретная версия конкретного пакета). Суммарная еженедельная аудитория этих пакетов превышает 16 миллионов загрузок. Такая цифра означает, что потенциально вредоносные обновления могли попасть в тысячи проектов за считанные часы.
Исследователи обратили внимание на необычный паттерн публикаций. Обычно даже крупные монорепозитории, подобные AntV, выпускают новые версии пачками, но это происходит не в две синхронные волны, а с некоторым разбросом во времени. Здесь же картина была иной. Первая волна составила 317 версий, опубликованных за семнадцать минут. Вторая - 314 версий, уложившихся всего в шесть секунд. Ещё две версии появились за сутки до основных волн. Такое поведение невозможно для легитимного процесса релиза, даже если все пакеты принадлежат одному монорепозиторию.
Ключевой индикатор атаки - то, что действие затронуло не только пакеты AntV. В списке перевыпущенных оказались совершенно независимые проекты, не связанные ни друг с другом, ни с Alibaba. Среди них size-sensor, jest-date-mock, jest-canvas-mock, echarts-for-react, timeago.js, timeago-react, filesize.js, byte-parser, xmorse, onfire.js, slice.js, ribbon.js, relationship.js, lint-md и целое семейство @lint-md/*, react-adsense, canvas-nest.js, boring-avatars-vanilla. Невозможно представить, чтобы все эти репозитории одновременно решили выпустить новые версии в одном и том же шестисекундном окне. Такую синхронность может создать только автоматизированный скрипт, использующий похищенный токен доступа.
Самые популярные пакеты, попавшие под удар, вызывают наибольшую тревогу. Так, jest-canvas-mock получает почти 3 миллиона загрузок в неделю. size-sensor - около 1,2 миллиона, echarts-for-react - более миллиона. Только эти три пакета в сумме генерируют более пяти миллионов еженедельных загрузок. Если бы злоумышленники внедрили вредоносный код в одну из таких библиотек, он мгновенно распространился бы по тысячам компьютеров разработчиков и конвейерам непрерывной интеграции.
Анализ атаки указывает на группу TeamPCP. Вероятнее всего, она получила доступ к учётной записи atool через фишинг, утечку токена автоматизации или компрометацию секретов в системе непрерывной интеграции. Характер публикаций (две плотные волны) больше соответствует использованию токена, чем интерактивной сессии. После получения доступа злоумышленники написали скрипт, который прошёлся по всем пакетам, принадлежащим аккаунту, и опубликовал новые версии. Это объясняет, почему вторая волна уложилась в шесть секунд - скрипт работал параллельно или использовал множественные подключения.
Теперь самое важное - анализ полезной нагрузки. Исследователи уже начали сравнение каждой новой версии с последней известной чистой. Они проверяют, был ли внедрён дополнительный код, изменены ли сценарии после установки (postinstall hooks), нет ли обфусцированных блоков или исходящих сетевых запросов. На данный момент результаты ещё не готовы, но очевидно, что масштаб случившегося требует немедленного внимания со стороны всего сообщества разработчиков.
Этот инцидент напоминает, насколько хрупкой может быть цепочка поставок программного обеспечения. Одна скомпрометированная учётная запись способна поставить под угрозу миллионы проектов. Разработчикам, использующим любой из затронутых пакетов, стоит временно зафиксировать версии, которые были выпущены до 18 мая 2026 года, и дождаться официальных результатов расследования. Компаниям, применяющим AntV и смежные библиотеки, нужно проверить свои системы на предмет аномальной активности. В своём отчёте OpenSourceMalware подчёркивает, что пока не обнаружено следов вредоносного кода, но окончательные выводы делать рано.
Ситуация также ставит вопрос о безопасности самого механизма публикации в npm. Использование автоматизированных токенов, хотя и удобно, создаёт дополнительные риски. Одним из решений могло бы стать внедрение обязательной многофакторной аутентификации для всех мейнтейнеров, особенно тех, кто управляет десятками или сотнями пакетов. Кроме того, полезно внедрить задержки при массовых публикациях - например, если один аккаунт выпускает более десяти пакетов за короткий промежуток времени, реестр мог бы запрашивать дополнительное подтверждение.
Пока инцидент остаётся предметом пристального внимания. Разработчикам из экосистемы Node.js стоит следить за обновлениями и быть готовыми к тому, что часть версий придётся отозвать. В конечном счёте этот случай ещё раз доказывает, что безопасность цепочки поставок - не абстрактная проблема, а ежедневная реальность, требующая постоянной бдительности.
Индикаторы компрометации
Скомпрометированная учетная запись
- npm maintainer: atool
Пакеты с самым высоким риском
- npm/echarts-for-react@3.0.7
- npm/echarts-for-react@3.1.7
- npm/echarts-for-react@3.2.7
- npm/jest-canvas-mock@2.5.3
- npm/jest-canvas-mock@2.6.3
- npm/jest-canvas-mock@2.7.3
- npm/jest-date-mock@1.0.11
- npm/jest-date-mock@1.1.11
- npm/jest-date-mock@1.2.11
- npm/size-sensor@1.0.4
- npm/size-sensor@1.1.4
- npm/size-sensor@1.2.4
Package
- @antv/a8 0.1.1, 0.2.1
- @antv/adjust 0.3.5, 0.4.5
- @antv/algorithm 0.2.26, 0.3.26
- @antv/async-hook 2.3.9, 2.4.9
- @antv/attr 0.4.5, 0.5.5
- @antv/ava 3.5.1, 3.6.1
- @antv/ava-react 3.4.2, 3.5.2
- @antv/awards 0.1.9, 0.2.9
- @antv/calendar-heatmap 1.2.2, 1.3.2
- @antv/chart-linter 1.2.6, 1.3.6
- @antv/chart-node-g6 0.1.4, 0.2.4
- @antv/chart-visualization-skills 0.2.3, 0.3.3
- @antv/ckb 2.1.4, 2.2.4
- @antv/color-schema 0.3.3, 0.4.3
- @antv/color-util 2.1.6, 2.2.6
- @antv/component 2.2.11, 2.3.11
- @antv/coord 0.5.7, 0.6.7
- @antv/d3-color 1.1.0, 1.2.0
- @antv/d3-interpolate 1.1.3, 1.2.3
- @antv/data-samples 1.1.1, 1.2.1
- @antv/data-set 0.12.8, 0.13.8
- @antv/data-wizard 2.1.4, 2.2.4
- @antv/dipper-component 0.1.4, 0.2.4
- @antv/dipper-hooks 0.3.1, 0.4.1
- @antv/dipper-map 1.1.10, 1.2.10
- @antv/dom-util 2.1.4, 2.2.4
- @antv/dumi-theme-antv 0.9.4, 0.10.4
- @antv/dw-analyzer 1.2.5, 1.3.5
- @antv/dw-random 1.2.7, 1.3.7
- @antv/dw-transform 1.2.7, 1.3.7
- @antv/dw-util 1.2.4, 1.3.4
- @antv/event-emitter 0.2.3, 0.3.3
- @antv/expr 1.1.2, 1.2.2
- @antv/f2-algorithm 5.8.0, 5.9.0
- @antv/f2-canvas 1.1.5, 1.2.5
- @antv/f2-context 0.1.1, 0.2.1
- @antv/f2-graphic 0.1.16, 0.2.16
- @antv/f2-my 4.1.52, 4.2.52
- @antv/f2-react 5.15.0, 5.16.0
- @antv/f2-site 4.1.42, 4.2.42
- @antv/f2-vue 4.1.33, 4.2.33
- @antv/f2-wordcloud 5.15.0, 5.16.0
- @antv/f2-wx 4.1.51, 4.2.51
- @antv/f6 0.1.19, 0.2.19
- @antv/f6-alipay 0.1.7, 0.2.7
- @antv/f6-core 0.1.2, 0.2.2
- @antv/f6-element 0.1.1, 0.2.1
- @antv/f6-hammerjs 0.1.2, 0.2.2
- @antv/f6-plugin 1.1.6, 1.2.6
- @antv/f6-ui 1.1.3, 1.2.3
- @antv/f6-wx 0.1.7, 0.2.7
- @antv/f-charts 0.1.0, 0.2.0
- @antv/f-engine 1.11.0, 1.12.0
- @antv/f-lottie 1.11.0, 1.12.0
- @antv/f-my 1.11.0, 1.12.0
- @antv/f-react 1.11.0, 1.12.0
- @antv/f-test-utils 1.1.9, 1.2.9
- @antv/f-vue 1.11.0, 1.12.0
- @antv/f-wx 1.11.0, 1.12.0
- @antv/g 6.4.1, 6.5.1
- @antv/g2 5.5.8, 5.6.8
- @antv/g2-brush 0.1.2, 0.2.2
- @antv/g2-extension-3d 0.3.0, 0.4.0
- @antv/g2-extension-ava 0.3.0, 0.4.0
- @antv/g2-extension-plot 0.3.2, 0.4.2
- @antv/g2plot 2.5.35, 2.6.35
- @antv/g2plot-schemas 1.3.2, 1.4.2
- @antv/g2-plugin-slider 2.2.1, 2.3.1
- @antv/g2-ssr 0.3.0, 0.4.0
- @antv/g6 5.2.1, 5.3.1
- @antv/g6-alipay 0.1.1, 0.2.1
- @antv/g6-cli 0.1.4, 0.2.4
- @antv/g6-core 0.9.24, 0.10.24
- @antv/g6-editor 1.3.0, 1.4.0
- @antv/g6-element 0.9.25, 0.10.25
- @antv/g6-extension-3d 0.2.23, 0.3.23
- @antv/g6-extension-react 0.3.7, 0.4.7
- @antv/g6-lite 0.1.0-beta.1
- @antv/g6-mobile 0.2.2, 0.3.2
- @antv/g6-pc 0.9.25, 0.10.25
- @antv/g6-plugin 0.9.25, 0.10.25
- @antv/g6-plugin-map-view 0.1.4, 0.2.4
- @antv/g6-plugins 1.1.9, 1.2.9
- @antv/g6-react-node 1.5.8, 1.6.8
- @antv/g6-ssr 0.2.1, 0.3.1
- @antv/g6-wx 0.1.1, 0.2.1
- @antv/gatsby-theme 0.2.0, 0.3.0
- @antv/g-base 0.6.16, 0.7.16
- @antv/g-camera-api 2.1.45, 2.2.45
- @antv/g-canvas 2.3.0, 2.4.0
- @antv/g-canvaskit 1.2.1, 1.3.1
- @antv/g-compat 1.1.11, 1.2.11
- @antv/g-components 2.1.42, 2.2.42
- @antv/g-css-layout-api 1.1.38, 1.2.38
- @antv/g-css-typed-om-api 1.1.38, 1.2.38
- @antv/g-device-api 1.7.13, 1.8.13
- @antv/g-dom-mutation-observer-api 2.1.42, 2.2.42
- @antv/geo-coord 1.1.8, 1.2.8
- @antv/g-gesture 3.1.42, 3.2.42
- @antv/gi-assets-advance 2.6.22, 2.7.22
- @antv/gi-assets-algorithm 2.4.19, 2.5.19
- @antv/gi-assets-basic 2.5.40, 2.6.40
- @antv/gi-assets-galaxybase 1.3.15, 1.4.15
- @antv/gi-assets-graphscope 2.2.15, 2.3.15
- @antv/gi-assets-hugegraph 1.2.15, 1.3.15
- @antv/gi-assets-janusgraph 1.2.15, 1.3.15
- @antv/gi-assets-neo4j 2.2.15, 2.3.15
- @antv/gi-assets-scene 2.3.21, 2.4.21
- @antv/gi-assets-tugraph 2.2.15, 2.3.15
- @antv/gi-assets-tugraph-analytics 0.3.15, 0.4.15
- @antv/gi-assets-xlab 0.2.30, 0.3.30
- @antv/gi-cli 1.3.11, 1.4.11
- @antv/gi-common-components 1.4.16, 1.5.16
- @antv/g-image-exporter 1.1.42, 1.2.42
- @antv/gi-mock-data 1.1.5, 1.2.5
- @antv/gi-public-data 1.1.1, 1.2.1
- @antv/gi-sdk 3.1.0, 3.2.0
- @antv/gi-sdk-app 1.3.10, 1.4.10
- @antv/gi-theme-antd 0.7.11, 0.8.11
- @antv/github-config-cli 0.2.0, 0.3.0
- @antv/g-layout-blocklike 1.8.49, 1.9.49
- @antv/g-lite 2.8.0, 2.9.0
- @antv/gl-matrix 2.8.1, 2.9.1
- @antv/g-lottie-player 1.2.1, 1.3.1
- @antv/g-math 3.2.0, 3.3.0
- @antv/g-mobile 1.2.5, 1.3.5
- @antv/g-mobile-canvas 1.2.1, 1.3.1
- @antv/g-mobile-canvas-element 1.1.42, 1.2.42
- @antv/g-mobile-svg 1.2.1, 1.3.1
- @antv/g-mobile-webgl 1.2.1, 1.3.1
- @antv/g-pattern 2.1.42, 2.2.42
- @antv/g-perf 1.1.0, 1.2.0
- @antv/g-plugin-3d 2.2.1, 2.3.1
- @antv/g-plugin-a11y 1.5.1, 1.6.1
- @antv/g-plugin-annotation 1.3.0, 1.4.0
- @antv/g-plugin-box2d 2.2.1, 2.3.1
- @antv/g-plugin-canvaskit-renderer 2.4.1, 2.5.1
- @antv/g-plugin-canvas-path-generator 2.2.26, 2.3.26
- @antv/g-plugin-canvas-picker 2.4.1, 2.5.1
- @antv/g-plugin-canvas-renderer 2.6.1, 2.7.1
- @antv/g-plugin-control 2.2.1, 2.3.1
- @antv/g-plugin-css-select 2.2.1, 2.3.1
- @antv/g-plugin-device-renderer 2.7.1, 2.8.1
- @antv/g-plugin-dom-interaction 2.2.31, 2.3.31
- @antv/g-plugin-dragndrop 2.2.1, 2.3.1
- @antv/g-plugin-gesture 2.2.1, 2.3.1
- @antv/g-plugin-gpgpu 1.10.20, 1.11.20
- @antv/g-plugin-html-renderer 2.4.1, 2.5.1
- @antv/g-plugin-image-loader 2.4.1, 2.5.1
- @antv/g-plugin-matterjs 2.2.1, 2.3.1
- @antv/g-plugin-mobile-interaction 1.1.42, 1.2.42
- @antv/g-plugin-physx 2.2.1, 2.3.1
- @antv/g-plugin-rough-canvas-renderer 2.2.1, 2.3.1
- @antv/g-plugin-rough-svg-renderer 2.2.1, 2.3.1
- @antv/g-plugin-svg-picker 2.1.46, 2.2.46
- @antv/g-plugin-svg-renderer 2.5.1, 2.6.1
- @antv/g-plugin-webgl-device 1.10.17, 1.11.17
- @antv/g-plugin-webgl-renderer 1.1.26, 1.2.26
- @antv/g-plugin-webgpu-device 1.10.17, 1.11.17
- @antv/g-plugin-yoga 2.4.1, 2.5.1
- @antv/g-plugin-zdog-canvas-renderer 2.2.1, 2.3.1
- @antv/g-plugin-zdog-svg-renderer 2.2.1, 2.3.1
- @antv/gpt-vis 1.1.0, 1.2.0
- @antv/gpt-vis-ssr 0.4.7, 0.5.7
- @antv/graphin 3.1.5, 3.2.5
- @antv/graphin-components 2.5.1, 2.6.1
- @antv/graphin-graphscope 1.1.5, 1.2.5
- @antv/graphin-icons 1.1.0, 1.2.0
- @antv/graphlib 2.1.4, 2.2.4
- @antv/g-shader-components 2.1.0, 2.2.0
- @antv/g-svg 2.2.1, 2.3.1
- @antv/g-web-animations-api 2.2.32, 2.3.32
- @antv/g-web-components 2.2.1, 2.3.1
- @antv/g-webgl 2.2.1, 2.3.1
- @antv/g-webgl-compute 0.1.1, 0.2.1
- @antv/g-webgpu 2.2.1, 2.3.1
- @antv/g-webgpu-compiler 0.8.2, 0.9.2
- @antv/g-webgpu-core 0.8.2, 0.9.2
- @antv/g-webgpu-engine 0.8.2, 0.9.2
- @antv/g-webgpu-raytracer 0.6.1, 0.7.1
- @antv/g-webgpu-unitchart 0.6.1, 0.7.1
- @antv/hierarchy 0.8.1, 0.9.1
- @antv/infographic 0.3.19, 0.4.19
- @antv/insight-component 1.1.0, 1.2.0
- @antv/interaction 0.2.5, 0.3.5
- @antv/istanbul 0.1.0, 0.2.0
- @antv/knowledge 1.2.4, 1.3.4
- @antv/l7 2.26.10, 2.27.10
- @antv/l7-component 2.26.10, 2.27.10
- @antv/l7-composite-layers 0.18.1, 0.19.1
- @antv/l7-core 2.26.10, 2.27.10
- @antv/l7-district 2.4.12, 2.5.12
- @antv/l7-draw 3.2.5, 3.3.5
- @antv/l7-editor 1.2.13, 1.3.13
- @antv/l7-extension-g-layer 1.1.0, 1.2.0
- @antv/l7-layers 2.26.10, 2.27.10
- @antv/l7-leaflet 1.1.2, 1.2.2
- @antv/l7-map 2.26.10, 2.27.10
- @antv/l7-mapkit 0.6.0, 0.7.0
- @antv/l7-maps 2.26.10, 2.27.10
- @antv/l7-mini 2.21.8, 2.22.8
- @antv/l7-pass 1.1.0, 1.2.0
- @antv/l7plot 0.6.11, 0.7.11
- @antv/l7plot-component 0.1.11, 0.2.11
- @antv/l7-react 2.5.3, 2.6.3
- @antv/l7-renderer 2.26.10, 2.27.10
- @antv/l7-scene 2.26.10, 2.27.10
- @antv/l7-source 2.26.10, 2.27.10
- @antv/l7-three 2.26.10, 2.27.10
- @antv/l7-utils 2.26.10, 2.27.10
- @antv/larkmap 1.6.1, 1.7.1
- @antv/layout-gpu 1.2.7, 1.3.7
- @antv/layout-wasm 1.5.2, 1.6.2
- @antv/li-aiearth-assets 0.5.7, 0.6.7
- @antv/li-analysis-assets 1.10.1, 1.11.1
- @antv/li-core-assets 1.4.7, 1.5.7
- @antv/li-editor 1.7.1, 1.8.1
- @antv/li-p2 1.9.2, 1.10.2
- @antv/li-sam-assets 0.2.4, 0.3.4
- @antv/li-sdk 1.6.1, 1.7.1
- @antv/lite-insight 2.2.1, 2.3.1
- @antv/matrix-util 3.1.4, 3.2.4
- @antv/mcp-server-antv 0.2.8, 0.3.8
- @antv/mcp-server-chart 0.10.10, 0.11.10
- @antv/my-f2 2.2.7, 2.3.7
- @antv/my-f2-pc 0.2.1, 0.3.1
- @antv/narrative-text-editor 0.3.20, 0.4.20
- @antv/narrative-text-schema 0.4.7, 0.5.7
- @antv/narrative-text-vis 0.4.16, 0.5.16
- @antv/path-util 3.1.1, 3.2.1
- @antv/react-g 2.2.1, 2.3.1
- @antv/s2 2.8.1, 2.9.1
- @antv/s2-react 2.4.1, 2.5.1
- @antv/s2-react-components 2.2.2, 2.3.2
- @antv/s2-ssr 0.2.1, 0.3.1
- @antv/s2-vue 2.3.0, 2.4.0
- @antv/sam 0.3.0, 0.4.0
- @antv/scale 0.6.2, 0.7.2
- @antv/semantic-release-pnpm 1.1.4, 1.2.4
- @antv/smart-color 0.3.1, 0.4.1
- @antv/stat 0.1.2, 0.2.2
- @antv/t8 0.4.0, 0.5.0
- @antv/thumbnails 2.1.0, 2.2.0
- @antv/thumbnails-component 2.1.0, 2.2.0
- @antv/torch 1.1.6, 1.2.6
- @antv/translator 1.1.1, 1.2.1
- @antv/util 3.4.11, 3.5.11
- @antv/vendor 1.1.11, 1.2.11
- @antv/vis-predict-engine 0.2.1, 0.3.1
- @antv/webgpu-graph 1.1.0, 1.2.0
- @antv/word-scale-chart 0.4.4, 0.5.4
- @antv/wx-f2 2.2.1, 2.3.1
- @antv/x6 3.2.7, 3.3.7
- @antv/x6-angular-shape 3.1.1, 3.2.1
- @antv/x6-common 2.1.17, 2.2.17
- @antv/x6-components 0.11.7, 0.12.7
- @antv/x6-plugin-clipboard 2.2.6, 2.3.6
- @antv/x6-plugin-dnd 2.2.1, 2.3.1
- @antv/x6-plugin-export 2.2.6, 2.3.6
- @antv/x6-plugin-history 2.3.4, 2.4.4
- @antv/x6-plugin-keyboard 2.3.3, 2.4.3
- @antv/x6-plugin-minimap 2.1.7, 2.2.7
- @antv/x6-plugin-scroller 2.1.10, 2.2.10
- @antv/x6-plugin-selection 2.3.2, 2.4.2
- @antv/x6-plugin-snapline 2.2.7, 2.3.7
- @antv/x6-plugin-stencil 2.2.5, 2.3.5
- @antv/x6-plugin-transform 2.2.8, 2.3.8
- @antv/x6-react 0.2.26, 0.3.26
- @antv/x6-react-components 2.1.9, 2.2.9
- @antv/x6-react-shape 3.1.1, 3.2.1
- @antv/x6-vector 1.5.2, 1.6.2
- @antv/x6-vue3-shape 1.1.0, 1.2.0
- @antv/x6-vue-shape 3.1.2, 3.2.2
- @antv/xflow 2.2.13, 2.3.13
- @antv/xflow-core 1.1.55, 1.2.55
- @antv/xflow-diff 1.1.0, 1.2.0
- @antv/xflow-extension 1.1.55, 1.2.55
- @antv/xflow-hook 1.1.55, 1.2.55
- @lint-md/cli 2.1.0, 2.2.0
- @lint-md/core 2.1.0, 2.2.0
- @lint-md/parser 0.1.14, 0.2.14
- ai-figure 0.5.0, 0.6.0
- amapcn 0.1.2, 0.2.2, 0.3.2
- ast-plugin 0.1.7, 0.2.7
- babel-plugin-version 0.3.3, 0.4.3
- boring-avatars-vanilla 1.1.2, 1.2.2
- byte-parser 1.1.0, 1.2.0
- canvas-nest.js 2.1.4, 2.2.4
- echarts-for-react 3.0.7, 3.1.7, 3.2.7
- filesize.js 2.1.0, 2.2.0
- fixed-round 1.1.2, 1.2.2
- gantt-for-react 0.3.0, 0.4.0
- jest-canvas-mock 2.5.3, 2.6.3, 2.7.3
- jest-date-mock 1.0.11, 1.1.11, 1.2.11
- jest-electron 0.2.12, 0.3.12
- jest-expect 0.1.1, 0.2.1
- jest-less-loader 0.3.0, 0.4.0
- jest-random-mock 1.1.0, 1.2.0
- jest-url-loader 0.2.0, 0.3.0
- limit-size 0.2.4, 0.3.4
- lint-md 0.3.0, 0.4.0
- lint-md-cli 0.2.2, 0.3.2
- mcp-echarts 0.8.1, 0.9.1
- mcp-mermaid 0.5.1, 0.6.1
- miz 1.1.1, 1.2.1
- onfire.js 2.1.1, 2.2.1
- react-adsense 0.2.0, 0.3.0
- relationship.js 1.3.9, 1.4.9
- ribbon.js 01.01.2002
- size-sensor 1.0.4, 1.1.4, 1.2.4
- slice.js 1.2.1, 1.3.1
- timeago.js 4.1.2, 4.2.2
- timeago-react 3.1.7, 3.2.7
- word-width 1.1.1, 1.2.1
- xmorse 1.1.0, 1.2.0