Материал

Dependency Confusion: как коллизия имён в реестрах превращается в RCE и что с этим делать

Механика private/public name collision, реальные взломы и практический список защит — от naming-конвенций до review-политики для каждого PR

Почему это важно прямо сейчас

Dependency confusion — не экзотика и не академический эксперимент. OWASP включил Software Supply Chain Failures в проект своего Top 10 2025 сразу на третью строку [4]. Verizon DBIR 2025 зафиксировал удвоение доли взломов через третью сторону: с 15% до 30% за год [5].

При этом сама механика атаки принципиально не изменилась с 2021 года — изменился контекст: команды стали быстрее, CI/CD плотнее, а AI-ассистенты добавили новый источник фантомных зависимостей прямо в pull request. Если ваш разработчик принял PR с кодом от Copilot, не проверив имена пакетов, атака может пройти до merge — тихо, без алертов.

Что такое dependency confusion: механика name collision

Каждый package manager — npm, pip, RubyGems, NuGet, Maven — умеет работать с несколькими источниками одновременно: приватным корпоративным реестром и публичным (npmjs.com, pypi.org и т.д.). Именно в этом «одновременно» и зарыта проблема.

Когда build system запрашивает пакет и находит его и в приватном реестре, и в публичном, она руководствуется простым правилом: берётся версия с наибольшим номером. Это поведение по умолчанию у npm, pip при использовании --extra-index-url и у ряда прокси-решений вроде JFrog Artifactory и Sonatype Nexus при конфигурации виртуального репозитория [6].

Схема атаки пошагово:

  1. Атакующий находит имя приватного пакета. Источников много: package.json в публичном GitHub-репозитории, сообщения об ошибках npm, вакансии, внутренняя документация, случайно опубликованные конфиги [1][7].
  2. Публичный реестр не содержит такого пакета — имя свободно.
  3. Атакующий регистрирует пакет с тем же именем и устанавливает версию 9.9.9 или выше — заведомо выше реальной.
  4. В пакет добавляется postinstall скрипт, который выполняется сразу после установки: эксфильтрация данных, reverse shell или маячок через DNS [1].
  5. Следующий npm install / pip install в CI/CD или на машине разработчика тянет публичный пакет — build system «выбирает лучшее».

Именно так Бирсан попал внутрь Apple, Microsoft, Netflix, Uber и ещё 30 компаний. Из сетей Apple выполнялся код на разработческих машинах darwin x64; из инфраструктуры Netflix запросы приходили с macOS CI-раннеров [1][7].

Откуда берутся имена приватных пакетов

Это ключевой вопрос — без имени атаки нет. Источники обнаружения приватных имён:

  • package.json, requirements.txt, pom.xml и другие манифесты в публичных репозиториях на GitHub/GitLab;
  • сообщения об ошибках npm, которые могут раскрывать имя registry;
  • внутренние пакеты, случайно опубликованные на публичных реестрах;
  • сообщения на форумах и Stack Overflow с фрагментами кода;
  • вакансии, где упоминаются внутренние библиотеки;
  • JS source maps и bundle-файлы, которые доступны в продакшне [11].

pip: особый случай с --extra-index-url

В Python ситуация хуже, чем в npm. Флаг --extra-index-url по замыслу добавляет индекс в дополнение к дефолтному pypi.org — и pip выбирает пакет с максимальным номером версии из всех индексов. Это «небезопасно по дизайну», как описал сам Бирсан [10]. Правильная альтернатива — --index-url (единственный источник). Использование --extra-index-url с приватным реестром при наличии одноимённого пакета в PyPI — прямой путь к компрометации.

Реальные кейсы: от исследования до продакшн-взломов

2021: Бирсан и 35 компаний

Алекс Бирсан в феврале 2021 года опубликовал writeup о том, как методично взломал более 35 крупных организаций [1]. Bounty-выплаты: Microsoft — $40 000, Apple, Shopify, PayPal — по $30 000 каждая. Суммарно исследователь заработал более $130 000. Microsoft присвоила проблеме CVE-2021-24105 и опубликовала whitepaper с тремя стратегиями защиты [8].

2024: Netflix — developer laptop как точка входа

В октябре 2024 года через атаку dependency confusion был достигнут RCE в инфраструктуре Netflix. Пакет nf-cl-logger содержал типичный Netflix-префикс nf и не существовал в публичном npm. После публикации в течение 36 часов пришли запросы с IP-адресов Netflix Streaming Services — с машин darwin x64, то есть с ноутбуков разработчиков или ephemeral macOS CI-раннеров [9].

2024: Apache archived project

В марте 2024 года команда Legit Security обнаружила dependency confusion в архивированном проекте Apache. Команда безопасности Apache приняла стандартное решение: зарегистрировать публичную-«пустышку» с тем же именем, чтобы заблокировать вектор захвата имени [2].

2022: PyTorch — атака через частичное имя

В декабре 2022 года пакет torchtriton был подменён через PyPI. Разработчики PyTorch, установившие nightly-сборку, получили малварь, которая собирала SSH-ключи и другие чувствительные данные. PyTorch отреагировал, изменив схему именования пакетов [10].

2025: slopsquatting как новое поколение confusion-атак

Изображение

Исследование трёх университетов — University of Texas at San Antonio, University of Oklahoma, Virginia Tech — в 2025 году показало: LLM-ассистенты галлюцинируют несуществующие пакеты в ~20% случаев для open-source моделей и ~5% для коммерческих [3][16]. Среди 576 000 сгенерированных кодовых сэмплов было обнаружено более 200 000 уникальных несуществующих имён пакетов, причём 58% повторялись хотя бы дважды в 10 запусках — то есть это не случайный шум, а предсказуемые артефакты, которые можно картировать и занять превентивно [18].

Механика та же, что у классического dependency confusion: атакующий наблюдает, какие имена галлюцинирует конкретная модель для конкретных промптов, регистрирует эти пакеты заранее и ждёт, когда разработчик запустит pip install на код от ИИ-ассистента.

Почему стандартные конфигурации не защищают

Типичная ошибка — считать, что приватный реестр автоматически означает безопасность. Это не так. Проблемы возникают из-за:

Hybrid feed configuration. JFrog Artifactory, Sonatype Nexus, Azure Artifacts — все эти инструменты поддерживают виртуальные репозитории, которые агрегируют локальные и удалённые (публичные) источники под одним URL. Если не настроены exclude patterns или priority rules, пакет с высокой версией из публичного реестра победит приватный [20].

Параллельное разрешение. Часть package managers при использовании нескольких индексов опрашивает их параллельно и берёт максимальную версию — независимо от источника [6].

Отсутствие lock-файла. Версии без pin — ^1.0.0 или >=2.0 — позволяют установить любую более высокую версию. Если атакующий публикует 99.0.0, build system выберет именно её [13].

Кэш CI/CD. Build агенты, которые не сбрасываются до начального состояния после каждого билда, могут кэшировать скомпрометированные пакеты и распространять их дальше [11].

Практический список защит

Ни одна мера не является серебряной пулей. Безопасная конфигурация — это несколько слоёв, каждый из которых перекрывает слепые пятна предыдущего.

1. Naming: scoped packages и внутренние конвенции

Первый и самый важный слой. Организационный скоуп в npm (@company/package-name) означает, что namespace принадлежит вашей организации — никто другой не может опубликовать пакет в этом скоупе [4]. Аналоги есть в других экосистемах: NuGet поддерживает ID Prefix Reservation, Maven — Group ID.

Ключевые правила:

  • Зарегистрируйте скоуп на публичном реестре, даже если не планируете публиковать туда пакеты.
  • Применяйте скоуп ко всем внутренним пакетам без исключений — включая legacy и deprecated.
  • В .npmrc явно привяжите скоуп к приватному реестру: @company:registry=https://your.registry.example.com.
  • Если legacy-код использует неscoped имена — зарезервируйте эти имена на публичном реестре, опубликовав пустой placeholder-пакет с описанием и ссылкой на внутреннюю документацию [14].

Atlassian стала жертвой Бирсана именно потому, что использовала корпоративный скоуп внутри, но не зарегистрировала его на npm — исследователь занял его первым [10].

2. Registry pinning: один источник истины

Microsoft в своём whitepaper называет это первым приоритетом: использовать единственный приватный feed, который сам проксирует нужные публичные пакеты [8]. Это означает:

  • Все зависимости — и публичные, и приватные — резолвятся через ваш registry (Artifactory, Nexus, AWS CodeArtifact, Azure Artifacts, GitHub Packages).
  • Package manager настроен на единственный источник, публичный интернет недоступен напрямую из CI/CD.
  • Если registry временно недоступен — build падает, а не фолбэчится на публичный реестр.

Для pip: используйте только --index-url, никогда --extra-index-url для приватных пакетов. Для npm: registry= в .npmrc без дублирования источников.

3. Allowlist и exclude patterns в registry

Если вы используете hybrid feed (Artifactory virtual repo, Nexus group), настройте exclude patterns: явно укажите, какие имена пакетов никогда не должны резолвиться из публичного upstream [20].

  • В Artifactory: exclude patterns на remote repository блокируют запросы к публичному реестру для перечисленных имён.
  • В Nexus: аналогичная конфигурация через Content Selectors.
  • Принцип allowlist: публичный upstream разрешён только для явно одобренных пакетов и версий. Всё остальное — только из локального хранилища.

Google Cloud Artifact Registry в своей документации прямо указывает: инструменты, которые не позволяют контролировать порядок поиска при смешанной конфигурации, уязвимы к dependency confusion, и рекомендует использовать remote + virtual repository именно для минимизации этого риска [19].

4. Version pinning и integrity verification

Фиксация конкретной версии в lock-файле — не панацея, но существенно сужает окно для атаки:

  • Используйте package-lock.json (npm) или yarn.lock, poetry.lock (Python), Gemfile.lock (Ruby) — и коммитьте их в репозиторий.
  • В CI/CD используйте npm ci вместо npm install: команда устанавливает строго то, что указано в lock-файле, без обновления версий.
  • Lock-файл содержит поле integrity — хэш (SRI) tarball-файла. Если пакет подменён, хэш не совпадёт и установка упадёт [16].
  • Pinning защищает от автоматической установки более высокой версии, но не защищает первую установку на пустом окружении без lock-файла.

5. Install policy: postinstall scripts и egress

Postinstall скрипты — любимый инструмент атакующих. Именно они позволили Бирсану мгновенно получить DNS-эксфильтрацию после установки [1][12]:

  • Запретите выполнение lifecycle scripts при установке: npm config set ignore-scripts true. Это глобальная настройка для CI; на machine разработчика — отдельное решение с компромиссами [17].
  • Для pip: используйте --no-build-isolation и --require-hashes для строгой верификации.
  • На уровне сети: ограничьте исходящие соединения из CI/CD. Build environment не должен иметь произвольного доступа в интернет. Соединения с публичными реестрами — только через ваш proxy/registry.
  • Мониторьте DNS-запросы из build-окружения: внезапные внешние DNS-запросы при установке пакетов — индикатор компрометации.

6. Code review зависимостей: gate до merge

Технические меры не закрывают человеческий фактор: разработчик добавил новый пакет, PR прошёл ревью кода логики, но никто не посмотрел на изменения в package.json внимательно. Особенно это актуально при использовании AI-ассистентов, которые могут предложить несуществующий пакет [18][15]:

  • Каждое изменение в package.json, requirements.txt, go.mod, pom.xml и lock-файлах должно проходить явный security review, отдельный от логики кода.
  • Проверяйте: существует ли пакет в публичном реестре? Когда он был создан? Кто maintainer? Совпадает ли имя с внутренними библиотеками?
  • Для пакетов, добавленных AI-ассистентами: верифицируйте каждое имя вручную — не доверяйте тому, что пакет «звучит правильно».
  • Инструменты SCA (Snyk, Socket, OWASP Dependency-Check, Dependabot) умеют детектировать потенциальные dependency confusion: незарегистрированные scoped packages, пакеты с незаявленными высокими версиями, новые пакеты с именами, схожими с внутренними [12].

Именно здесь PR-review превращается в security gate: новая или обновлённая зависимость в диффе — сигнал, требующий отдельного внимания, независимо от того, кто написал код — человек или ИИ.

Как это работает в разных экосистемах

npm / Node.js

Наиболее задокументированная экосистема. Уязвимость возникает при конфигурации нескольких source registry без явного scope pinning [4]:

# .npmrc — безопасная конфигурация
@company:registry=https://your.private.registry.com
registry=https://registry.npmjs.org

При такой конфигурации @company/* пакеты разрешаются только из приватного реестра. Пакеты без скоупа — из npm. Риск: пакеты без скоупа по-прежнему могут стать жертвой confusion, если их имена совпадают с внутренними.

Python / pip

Самая опасная конфигурация — --extra-index-url. Безопасная альтернатива:

pip install --index-url https://your.private.registry.com/simple/ package-name

Ещё надёжнее — --require-hashes в сочетании с полным lock-файлом (pip-tools, Poetry).

Maven / Java

Group ID работает как namespace. Зарегистрируйте свой Group ID на Maven Central. Используйте <repositories> с явным указанием <releases> и <snapshots> и не добавляйте публичные репозитории в settings.xml без необходимости.

NuGet / .NET

NuGet поддерживает ID Prefix Reservation на nuget.org. Зарезервированный префикс визуально отмечается на странице пакета. Microsoft рекомендует это как один из трёх основных методов защиты [8][11].


Чек-лист: что проверить прямо сейчас

Naming:

  • [ ] Все внутренние пакеты используют скоуп/namespace.
  • [ ] Скоуп зарегистрирован на публичном реестре.
  • [ ] Unscoped внутренние пакеты зарезервированы как placeholders.

Registry:

  • [ ] CI/CD использует единственный registry-источник.
  • [ ] Приватный registry не фолбэчится на публичный при недоступности.
  • [ ] Virtual/group репозиторий настроен с exclude patterns для внутренних имён.
  • [ ] --extra-index-url в pip не используется для внутренних пакетов.

Versioning:

  • [ ] Lock-файлы коммитятся в репозиторий.
  • [ ] CI использует npm ci / pip install --require-hashes.
  • [ ] Integrity-хэши верифицируются при установке.

Install policy:

  • [ ] ignore-scripts=true в CI/CD конфигурации npm.
  • [ ] Egress из build environment ограничен.
  • [ ] DNS-аномалии в build окружении мониторятся.

Review:

  • [ ] Изменения в dependency-файлах проходят явный security review.
  • [ ] SCA инструмент интегрирован в pipeline и проверяет новые зависимости.
  • [ ] Пакеты из AI-сгенерированного кода верифицируются вручную.
  • [ ] Внутренние пакетные имена не присутствуют в публичных репозиториях и конфигах.

Ошибки, которые совершают даже опытные команды

«Приватный registry — значит защищены». Нет. Hybrid feed без правильных exclude patterns остаётся уязвимым. Именно так были скомпрометированы многие CI/CD среды.

«У нас lock-файл — мы в безопасности». Lock-файл защищает повторные установки, но не первую. Если разработчик добавил пакет без проверки, lock зафиксирует уже скомпрометированную версию.

«Мы используем скоуп». Если скоуп не зарегистрирован в публичном реестре — его можно занять. Atlassian использовал внутренний скоуп, но не зарегистрировал его на npm. Бирсан занял его и опубликовал туда пакеты [10].

«AI написал — значит пакет существует». LLM hallucinations создают plausible-sounding имена, которых нет в реестрах. Для коммерческих моделей ~5% предложений — несуществующие пакеты [16]. При масштабе команды 50 разработчиков, использующих AI-ассистенты, это десятки потенциальных slopsquatting-мишеней в неделю.

«Мы проверяем PR логики кода». Dependency changes в диффе часто теряются среди сотен строк бизнес-логики. Изменение в package.json — это изменение supply chain, требующее отдельного внимания.

Trend: от разовых атак к автоматизированной охоте

По данным GitGuardian, в течение 48 часов после публикации исследования Бирсана в 2021 году в npm появилось более 275 copycat-пакетов от разных атакующих [14]. Атака оказалась настолько тиражируемой, что её немедленно взяли на вооружение.

В 2025 году GhostAction — атака, зафиксированная GitGuardian 5 сентября — затронула 327 GitHub-пользователей и 817 репозиториев. Через вредоносные workflow злоумышленники эксфильтрировали 3325 секретов, включая токены PyPI, npm и DockerHub [6].

OWASP включил Software Supply Chain Failures в свой Top 10 2025 на третье место, отметив dependency confusion как один из ключевых векторов [14]. Это сигнал: тема перешла из категории «advanced threat» в категорию «baseline hygiene».

Слой контроля перед merge

Описанные выше меры хорошо работают как плановая гигиена, но у них есть общая слепая зона: они не отвечают на вопрос «что именно в этом конкретном PR несёт риск прямо сейчас». Lock-файл может быть корректным вчера и скомпрометированным сегодня, если новый пакет добавлен без проверки.

Именно для этого разрыва существуют инструменты review уровня PR — те, кто анализирует конкретное изменение в контексте: появилась новая зависимость, изменился lock-файл, добавлен postinstall скрипт. Такой подход позволяет не генерировать шум по всему репозиторию, а давать короткий ответ: «вот это изменение требует внимания, вот почему, вот следующий шаг».

HighVibe работает именно на этом уровне — анализирует конкретный PR, смотрит на новые и изменённые зависимости в диффе и помогает команде понять, можно ли безопасно принять изменение до merge, не перекладывая это на длинный SCA-отчёт, который дочитывают не всегда.

Что делать дальше

Dependency confusion — атака, которая не требует от злоумышленника доступа к вашей инфраструктуре. Только правильное имя и публичный реестр. При этом защита достаточно технически несложная — она требует дисциплины, а не экзотических инструментов.

Приоритет действий:

  1. Проведите инвентаризацию внутренних пакетных имён — особенно тех, что фигурируют в публичных репозиториях, конфигах и сообщениях об ошибках.
  2. Зарегистрируйте организационный namespace на публичных реестрах. Это бесплатно и занимает минуты.
  3. Переведите CI/CD на single-source registry с корректными exclude patterns.
  4. Добавьте проверку dependency-изменений в процесс code review как отдельный явный шаг.
  5. Верифицируйте пакеты из AI-генерируемого кода — slopsquatting растёт пропорционально росту AI-adoption.

Dependency confusion — не проблема пакетного менеджера. Это проблема доверия к автоматизации без контроля. И чем быстрее pipeline, тем важнее иметь gate, который смотрит на изменение прежде, чем оно уйдёт в продакшн.

Источники

[1] Medium / Alex Birsan — "Dependency Confusion: How I Hacked Into Apple, Microsoft and Dozens of Other Companies" — https://medium.com/@alex.birsan/dependency-confusion-how-i-hacked-into-apple-microsoft-and-dozens-of-other-companies-4a5d60fec610

[2] Legit Security — "Dependency Confusion Vulnerability Found in an Archived Apache Project" — https://www.legitsecurity.com/blog/dependency-confusion-vulnerability-found-in-an-archived-apache-project

[3] BleepingComputer — "AI-hallucinated code dependencies become new supply chain risk" — https://www.bleepingcomputer.com/news/security/ai-hallucinated-code-dependencies-become-new-supply-chain-risk/

[4] npm Docs — "Threats and Mitigations" — https://docs.npmjs.com/threats-and-mitigations/

[5] Cycode — "The 2025 OWASP Top 10: Addressing Software Supply Chain and LLM Risks" — https://cycode.com/blog/the-2025-owasp-top-10-addressing-software-supply-chain-and-llm-risks-with-cycode/

[6] GitGuardian — "Dependency Confusion Attacks and Prevention: Register Your Private Package Names" — https://blog.gitguardian.com/dependency-confusion-attacks/

[7] Arcjet — "Security Concepts for Developers: Dependency Confusion Attacks" — https://blog.arcjet.com/security-concepts-for-developers-dependency-confusion-attacks/

[8] Microsoft Azure — "3 Ways to Mitigate Risk When Using Private Package Feeds" — https://azure.microsoft.com/en-us/resources/3-ways-to-mitigate-risk-using-private-package-feeds/

[9] LandH.tech — "Netflix Vulnerability: Dependency Confusion in Action" — https://www.landh.tech/blog/20250610-netflix-vulnerability-dependency-confusion/

[10] Medium / Alex Birsan — "Dependency Confusion" (оригинальный writeup, pip / --extra-index-url, Atlassian) — https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610

[11] Security Scientist — "12 Questions and Answers About Dependency Confusion (Supply Chain)" — https://www.securityscientist.net/blog/12-questions-and-answers-about-dependency-confusion-supply-chain/

[12] Gridinsoft — "Researcher compromised 35 companies through new dependency confusion attack" — https://gridinsoft.com/blogs/researcher-compromised-35-companies-through-new-dependency-confusion-attack/

[13] Web Security Lens — "How Dependency Confusion attack works and How to prevent it" — https://www.websecuritylens.org/how-dependency-confusion-attack-works-and-how-to-prevent-it/

[14] GitGuardian — "Dependency Confusion Attacks and Prevention" (GhostAction, copycat packages, OWASP Top 10 2025) — https://blog.gitguardian.com/dependency-confusion-attacks/

[15] Snyk — "Detect and prevent dependency confusion attacks on npm to maintain supply chain security" — https://snyk.io/blog/detect-prevent-dependency-confusion-attacks-npm-supply-chain-security/

[16] Medium / InstaTunnel — "Dependency Confusion: The Supply Chain Attack in your package.json" — https://medium.com/@instatunnel/dependency-confusion-the-supply-chain-attack-in-your-package-json-9517dd17dbe8

[17] GitHub / lirantal — "npm Security Best Practices" — https://github.com/lirantal/npm-security-best-practices

[18] BleepingComputer — "AI-hallucinated code dependencies become new supply chain risk" (повторяемость 58%, данные arXiv) — https://www.bleepingcomputer.com/news/security/ai-hallucinated-code-dependencies-become-new-supply-chain-risk/

[19] Google Cloud Docs — "Remote repositories overview | Artifact Registry" — https://docs.cloud.google.com/artifact-registry/docs/repositories/remote-overview

[20] Foojay — "Namespace Shadowing (a.k.a. 'Dependency Confusion') Attack" — https://foojay.io/today/namespace-shadowing-a-k-a-dependency-confusion-attack/ твует в открытых исследованиях.

FAQ

Быстрые вопросы по теме

Что такое dependency confusion?

Это атака, основанная на коллизии имен пакетов в реестрах.

Как защититься от dependency confusion?

Используйте уникальные имена пакетов и проверяйте PR перед слиянием.

Какие инструменты помогают предотвратить атаки?

JFrog Artifactory и Sonatype Nexus с правильной конфигурацией.

Почему важна проверка имен пакетов?

Некорректные имена могут привести к установке вредоносных пакетов.

Каковы реальные примеры атак?

Атаки на Apple, Microsoft и Netflix через dependency confusion.

Нужен такой же контроль в ваших изменениях и релизах?

Покажем пример такого замечания на вашем сценарии и соберём пилотный контур без лишней суеты.

Запросить пилот Все статьи
Дальше по теме

Ещё материалы

Все статьи
02 мая 2026 18 мин безопасность

Как читать lock‑файл перед merge и не пропустить риск

Lock файл — это не шум на фоне кода. Это карта доверия к вашей зависимости. И именно через неё чаще всего приходит supply chain атака. TL;DR Lock файлы package lock.json, yarn.lock, poetry.lock фиксируют три вещи: верси…

Открыть материал
28 апреля 2026 17 мин AI

Кто отвечает за AI‑кодинг в команде: разработка, Tech Lead, DevOps или AppSec?

AI ускорил всех. Ответственность — нет TL;DR AI инструменты увеличивают скорость разработки, но вместе с ней — объём кода и число PR, которые никто не успевает прочитать целиком. Согласно исследованию Aikido Dev 2026 го…

Открыть материал
28 апреля 2026 18 мин AI

Как выбрать инструмент контроля AI-кодинга: 12 вопросов к вендору перед пилотом

Коммерческий спрос на инструменты контроля AI кодинга дорос до уровня, когда недостаточно просмотреть демо и прочитать лендинг. Нужен структурированный разговор с вендором — до того, как вы потратите три месяца на пилот…

Открыть материал