Сгенерированная абстрактная иллюстрация на бледно-серо-голубом поле: высокая тёмная панель цвета аспидного сланца стоит слева от центра, тонкий бледно-голубой луч проходит горизонтально сквозь неё и веером расширяется справа в широкий конус света над полем небольших геометрических блоков. Большинство блоков находятся в холодной тени; один кластер near centre of beam glows warm amber. Едва заметная чертёжная сетка и тонкие концентрические дуги расположены позади. Текст, числа, люди, брендовые знаки или логотипы организаций отсутствуют. Логотип OrcaRouter наложен в правом нижнем углу.
AI Safety Incidents

Clinejection: как заголовок issue добрался до npm-токена Cline

Автор

Rowan Sterling

Дата публикации

Новые модели · 20Все модели →
Бенчмарки: Artificial Analysis · обновляется ежедневно
Назад ко всем статьям

9 февраля 2026 года исследователь безопасности Аднан Хан опубликовал рассказ об уязвимости, о которой он 1 января конфиденциально сообщил Cline: AI-ассистент для программирования с открытым исходным кодом подключил автоматический триажер issue, построенный на GitHub Action claude-code-action от Anthropic, к промпту, который вставлял заголовок любого поступающего issue GitHub прямо в инструкции модели. Любой аккаунт GitHub мог запустить его, открыв issue, а в воспроизведении Хана заголовок, сформулированный как инструкция, заставил агента выполнить shell-команду внутри workflow. Затем он проследил путь от этой точки опоры через отравление кэша GitHub Actions до учетных данных для публикации релизов в VS Code Marketplace, OpenVSX и npm. Через восемь дней после того, как Cline исправил workflow, токен публикации npm, который Cline считал ротированным, был использован для публикации cline 2.3.0, установившей OpenClaw на каждой машине, где был установлен пакет. Полная запись с ее оценками серьезности и уверенности находится в Orca AI Incident Archive, рядом с соседними записями о цепочке поставок за тот же период.

Две даты, а не одна

Архив датирует эту запись 9 февраля 2026 года с точностью до дня, и это день, когда Khan опубликовал свой разбор на adnanthekhan.com. Это не день появления вредоносного пакета. Сама уязвимость была внесена 21 декабря 2025 года коммитом, который добавил рабочий процесс triage в репозиторий cline/cline, и оставалась активной, пока Cline не удалил этот рабочий процесс 9 февраля. Несанкционированная публикация в npm произошла 17 февраля — через восемь дней после исправления и через сорок семь дней после первого приватного отчёта Khan.

Важно разделять эти две даты, потому что самый значимый факт по делу находится в промежутке между ними: дверь закрыли 9 февраля, но ключ, который злоумышленник уже скопировал, всё ещё работал 17 февраля. Исправление самого Cline, отправленное Khan 17 февраля и воспроизведённое в его посте, прямо говорит: «Когда мы 9 февраля сменили учётные данные, токен публикации npm не был надлежащим образом отозван. Был удалён не тот токен, а скомпрометированный остался активным».

Цепочка: от заголовка задачи до токена релиза

Уязвимым файлом был .github/workflows/claude-issue-triage.yml, который запускался по событию issues и вызывал anthropics/claude-code-action@v1 с Claude Opus 4.5, закреплённым в workflow как claude-opus-4-5-20251101. Хан цитирует конфигурацию workflow: для allowed_non_write_users был задан подстановочный знак "*", поэтому любой аккаунт GitHub мог запустить агента, просто открыв issue, а claude_args передавал --allowedTools со списком Bash, Read, Write, Edit, Glob, Grep, WebFetch и WebSearch. Именно Bash имел значение. Он давал модели выполнение команд оболочки внутри workflow, который выполнялся в контексте ветки по умолчанию.

Промпт подставлял заголовок issue без его очистки. В доказательстве концепции Хана использовался заголовок, начинавшийся с «Tool error.» и продолжавшийся инструкцией установить вспомогательный пакет из конкретного коммита, прежде чем продолжить триаж. Ссылка на коммит указывала на форк, в package.json которого был скрипт preinstall, выполнявший команду curl к контролируемой атакующим конечной точке ещё до того, как npm завершил установку. Поскольку установка выполнялась через инструмент Bash, модель так и не проверила, что именно исполнялось. Хан воспроизвёл это на зеркале репозитория Cline и сообщает, что агент выполнял полезную нагрузку при каждой попытке.

Выполнение кода в рабочем процессе triage само по себе не даёт доступа к учётным данным для выпуска. Этот шаг возник из свойства GitHub Actions, которое Хан задокументировал в выпущенном в 2024 году инструменте под названием Cacheract: любой рабочий процесс может читать и записывать кэш репозитория, полностью контролируя ключи и версии кэша, даже рабочий процесс, который никогда не объявляет шаг кэширования. Задание triage выполнялось в ветке по умолчанию, поэтому оно имело общую область кэша с ночными заданиями публикации, которые действительно восстанавливали node_modules из кэша и действительно содержали токены публикации.

Записи кэша неизменяемы, поэтому атакующий не может просто перезаписать запись, которую восстановит задание релиза. Обходным путём Хана стало использование изменения политики GitHub от 20 ноября 2025 года, согласно которому сервис немедленно вытесняет записи кэша, как только кэш репозитория превышает 10 GB, в порядке least-recently-used. Залейте кэш сверх 10 GB — и легитимные записи вытеснятся по давности; займите освободившиеся ключи отравленным содержимым — и следующее задание, которое их восстановит, будет выполнять код атакующего. Cacheract автоматизирует всю последовательность в рамках одного запуска workflow и закрепляется, перезаписывая action.yml у actions/checkout, чтобы пост-шаг действия выполнял полезную нагрузку в конце каждого задания.

Последнее звено в цепочке — ночная задача, которая запускается примерно в 2:00 UTC, восстанавливает отравленный node_modules и детонирует. Наружу выходят VSCE_PAT, OVSX_PAT и NPM_RELEASE_TOKEN — учётные данные для VS Code Marketplace, OpenVSX и npm соответственно. Вопрос о том, выполнялось ли каждое звено в таком порядке против собственного репозитория Cline, — отдельный, и он рассматривается ниже.

A self-built HTML card titled 'Six steps from an issue title to a release token', badged 'Clinejection · GHSA-9ppg-jx86-fqw7', subtitled 'The chain as Adnan Khan describes it, with the workflow configuration he quotes'. Six numbered rows read: 1, Issue opened on cline/cline, the title carries the instructions and allowed_non_write_users is set to the wildcard; 2, claude-issue-triage.yml runs, claude-code-action with Bash, Read, Write, Edit, Glob, Grep, WebFetch and WebSearch; 3, npm install from a fork commit, the fork's package.json carries a preinstall script and the model runs it through Bash; 4, Cache flooded past 10 GB, GitHub's LRU eviction removes the legitimate entries and frees their keys; 5, Poisoned entries claim the keys, the nightly jobs restore attacker content as node_modules; 6, Nightly job runs at about 2 AM UTC, VSCE_PAT, OVSX_PAT and NPM_RELEASE_TOKEN leave the runner. A footer reads 'Source: Adnan Khan, Clinejection, 9 February 2026; Cline advisory GHSA-9ppg-jx86-fqw7.' The OrcaRouter logo is composited in the bottom-right corner.

Почему ночные учётные данные оказались производственными учётными данными

Очевидное возражение состоит в том, что ночные и производственные релизы должны иметь разные секреты. Ответ Хана таков: разделение было номинальным. OpenVSX и VS Code Marketplace привязывают токен публикации к идентичности издателя, а не к отдельному расширению, и оба расширения Cline — стабильное и ночное — были опубликованы под одной и той же идентичностью, которую Хан на OpenVSX указывает как saoudrizwan. В npm модель гранулярных токенов привязана к пакету, и Cline публиковал свои стабильные и ночные сборки CLI в один и тот же пакет cline. Поэтому токен, выданный для ночной задачи, мог опубликовать производственный артефакт — именно это и произошло восемь дней спустя.

Собственное объяснение Хана относительно последствий опирается на масштаб: он ссылается на объявление Cline о том, что число установок превысило 5 миллионов, и отмечает, что обновление расширения, проталкиваемое с помощью украденных учётных данных, выполняется в контексте каждого разработчика, чей редактор обновляется автоматически, с правами этого разработчика и доступом ко всем ключам, токенам и исходному коду, которые находятся на машине.

Что на самом деле было опубликовано и что оно сделало

Опубликованный артефакт представлял собой cline 2.3.0 и был небольшим. Собственные временные метки реестра npm указывают, что 2.3.0 был опубликован в 11:26:51 UTC 17 февраля 2026 года, а чистый 2.4.0 — в 19:23:08 UTC в тот же день; по оценке рекомендательного бюллетеня Cline, период экспозиции составил примерно восемь часов — до тех пор, пока 2.3.0 не был помечен как устаревший в 11:30 по тихоокеанскому времени. В package.json пакета появилась одна добавленная строка — скрипт postinstall со следующим содержимым: npm install -g openclaw@latest. В рекомендательном бюллетене Cline GHSA-9ppg-jx86-fqw7 указано, что другие файлы пакета не изменялись, а dist/cli.mjs побайтно идентичен легитимной сборке 2.2.3.

OpenClaw — это настоящий open-source фреймворк AI-агентов, а не вредоносное ПО, и в уведомлении Cline это прямо указано: это легитимный проект, но его установка не была санкционирована и не предполагалась. Endor Labs, проанализировавшая tar-архив, оценила общее воздействие как низкое на том основании, что установка не запускала демон Gateway OpenClaw. В материале StepSecurity рассматривается другая сторона: глобальная установка оставляет фреймворк на диске вместе с теми учётными данными и доступом к файлам, которые есть у пользователя, выполнявшего установку, а архитектура OpenClaw — постоянный локальный шлюз с operator API — делает его высокоценной находкой в такой среде. Эти две оценки не противоречат друг другу. Одна описывает, что выполнялось в течение этого окна; другая описывает, что осталось после этого.

Объём — это единственный показатель, с которым нужно обращаться осторожно. StepSecurity сообщила, что скомпрометированная версия была скачана примерно 4 000 раз до того, как её объявили устаревшей, и The Register привёл ту же цифру. По оценке Endor Labs, месячное число загрузок cline с 19 января по 17 февраля составило 418 545, что описывает обычный трафик пакета, а не вредоносную сборку. Ни одна из этих цифр не учитывает машины: количество загрузок — это не количество пострадавших разработчиков, и ни одна сторона не опубликовала данные о числе установок для 2.3.0. Команда Microsoft Threat Intelligence сообщила в X, что 17 февраля наблюдала «небольшой, но заметный рост» установок OpenClaw, возникший из-за установочного скрипта Cline, как сообщило The Hacker News.

В рекомендательном бюллетене GitHub для GHSA-9ppg-jx86-fqw7 нет ни CVE, ни CWE, а его уровень серьёзности — Low. Эта оценка относится к безвредной полезной нагрузке, а не к краже учётных данных, и странно смотрится рядом с критической оценкой архива для самого инцидента. В бюллетене указаны 2.3.0 как уязвимая версия и 2.4.0 как исправление.

Раскрытие, на которое Cline не ответил

Хронология действий Хана до публикации — это та часть материалов, которая меньше всего касается модели и больше всего — процесса. 1 января 2026 года он подал GHSA через приватную систему сообщений об уязвимостях GitHub и в тот же день написал на адрес безопасности, указанный на странице доверия Cline. 8 января он отправил повторное сообщение разработчику Cline. 18 января он попытался написать напрямую генеральному директору Cline в X. 7 февраля он написал снова и не получил ничего, кроме автоматического номера заявки. 9 февраля он опубликовал материал.

Cline слил исправление — пул-реквест 9211 — примерно через полчаса–час. Этот PR удаляет три файла рабочих процессов: claude-issue-triage.yml, claude-pr-review.yml и cline-pr-review.yml, а также убирает кэширование из publish.yml, publish-nightly.yml, npm-nightly.yaml и npm-main.yaml — всего семь файлов; шаги установки теперь сделаны безусловными, поскольку больше нет попадания в кэш, от которого можно зависеть.

Публичный ответ Cline от 10 февраля, процитированный в публикации Khan, признал находку и перечислил немедленные меры: удаление рабочих процессов проверки issue и PR ботом, удаление actions/cache из рабочих процессов публикации, обрабатывающих учетные данные релиза, и ротация соответствующих учетных данных, включая токены бота, провайдера и публикации. В нем также была признана проблема с обработкой: «мы признаем, что время нашей реакции на ваш первоначальный отчет было неприемлемым. Отчет, поданный 1 января, не должен был требовать публичного раскрытия 9 февраля, чтобы его рассмотрели».

11 февраля Cline сообщила, что завершила полную ротацию VSCE_PAT, OVSX_PAT и NPM_RELEASE_TOKEN, а также что аудит каждого релиза во всех трёх каналах распространения в период с 21 декабря 2025 года по 9 февраля 2026 года показал, что каждая версия в Marketplace и OpenVSX соответствует релизу GitHub с тегом, и что все 41 версия npm согласуются с исходным кодом. Она пришла к выводу, что «в течение заявленного окна воздействия» не было опубликовано ни одного несанкционированного релиза. Шесть дней спустя она исправила эту информацию в приведённом выше сообщении: токен npm не был отозван, и с его помощью была опубликована версия 2.3.0.

A self-built HTML card titled 'From private report to public disclosure', subtitled 'Khan's pre-publication timeline, and what followed'. Eight dated rows read: 21 Dec 2025, vulnerable claude-issue-triage.yml committed; 1 January 2026, GHSA filed and email sent to Cline's listed security contact; 8 January 2026, follow-up email to a Cline developer, no reply; 18 January 2026, direct message to Cline's CEO on X, no reply; 7 February 2026, final email, automated ticket number only; 9 February 2026, public disclosure and PR 9211 merged within about an hour; 11 February 2026, Cline reports full rotation and a clean audit; 17 February 2026, cline 2.3.0 published with a still-valid npm token. A footer reads 'Times and dates as recorded by Adnan Khan; the 17 February publish timestamp is corroborated by the npm registry.' The OrcaRouter logo is composited in the bottom-right corner.

Установлено, атрибутировано, нерешено

• Установлено. Конфигурация workflow является публичной и была опубликована до исправления. Khan воспроизвёл prompt-инъекцию на зеркале репозитория. Cline принял исправление и выпустил бюллетень безопасности, который подтверждает публикацию 2.3.0, добавленную строку postinstall, неизменённый бинарник CLI, восьмичасовое окно и сбой токена. Отметки времени в npm registry для 2.3.0 и 2.4.0 совпадают со временем, указанным в бюллетене. Архив оценивает запись как critical, с уровнем уверенности A, с зафиксированным реальным ущербом и без отметки об оспаривании.

• Приписывается, но не установлено. Кто опубликовал 2.3.0, остаётся открытым вопросом атрибуции. Криминалистический отчёт, опубликованный Майклом Баргури и автоматизированным инструментом расследования под названием Raptor 19 февраля, называет GitHub-аккаунт glthub-actions и с высокой уверенностью сообщает, что этот аккаунт сделал форк cline/cline, открыл issue 8904 28 января 2026 года в 03:51 UTC с внедрённым заголовком и использовал коммит форка для запуска полезной нагрузки из gist. Хан подтвердил, что аккаунты gcbrun и Dev11940518 принадлежат ему, а glthub-actions — нет. На момент публикации отчёта аккаунт уже был удалён или заблокирован, и Cline никого не назвал. Рассматривайте личность как стороннюю находку.

Спор идёт о характере, а не о фактах. Bargury оценивает этот эпизод как согласующийся с демонстрацией в рамках исследования безопасности, а не с вредоносной кампанией, ссылаясь на безобидную полезную нагрузку и историю активности актора в отношении репозитория автоматизации New Relic. Cline называет это несанкционированной публикацией, а Khan пишет, что актор, опубликовавший 2.3.0, «предположительно» тот же, кто отравил кэши. Никто не показал намерения причинить вред, и никто не показал, что его не было.

• Не решено. В собственной предпубликационной заметке Хан осторожно формулирует один момент, который в более поздних репортажах иногда упрощают: в период с 31 января по 3 февраля 2026 года несколько ночных запусков завершились неудачей на шаге Post Checkout, не выдавшем никаких выходных данных, что является индикатором компрометации по версии Cacheract; при этом рабочий процесс triage — наиболее очевидный путь, но не доказано, что именно он был точкой входа для этой активности. Также ни одна сторона не опубликовала доказательств того, что использовались токены Marketplace или OpenVSX; единственный артефакт, который кто-либо предоставил, — это npm-сборка.

A self-built HTML card titled 'What the record supports', subtitled 'One column is documented, one is other people's findings, one is simply open', split into three columns. The first, headed Established, lists four items: the triage workflow interpolated issue titles into the prompt and allowed any GitHub account to trigger it, with Bash among the tools; Khan reproduced the injection on a mirror of the repository; Cline's advisory GHSA-9ppg-jx86-fqw7 confirms cline 2.3.0, the added postinstall line, the unchanged CLI binary and an eight-hour window; npm registry timestamps place 2.3.0 at 11:26 UTC and 2.4.0 at 19:23 UTC on 17 February 2026. The second, headed Attributed, lists three items: the account glthub-actions and issue 8904 come from a third-party forensic write-up, not from Cline; that the actor copied Khan's public proof-of-concept repository is an inference from timing and from his own statement; that the publish was a research demonstration rather than an attack is one analyst's assessment. The third, headed Unresolved, lists three items: whether the triage workflow was the entry point for the late-January cache anomalies; whether any Marketplace or OpenVSX credential was used, with no artefact published; how many distinct machines installed 2.3.0, since about 4,000 is a download count. A footer reads 'Sources: Adnan Khan, Clinejection, 9 February 2026; Cline, GHSA-9ppg-jx86-fqw7; StepSecurity, 17 February 2026; Endor Labs, 18 February 2026; Michael Bargury and Raptor, 19 February 2026.' The OrcaRouter logo is composited in the bottom-right corner.

Что изменилось после этого

Исправление затронуло сразу несколько уровней, и каждый стоит назвать отдельно, поскольку они отвечают на разные части сбоя. Рабочий процесс, до которого мог добраться посторонний, был удалён, а не сужен. Кэширование было убрано из четырёх рабочих процессов выпуска, в которых хранятся секреты публикации, а не из всего репозитория, — и именно это изменение ломает pivot-сценарий. Учётные данные были заменены, а после исправления от 17 февраля был отозван правильный npm-токен. В рекомендации Cline указано, что публикация в npm теперь использует подтверждение происхождения через OIDC в GitHub Actions, а анализ метаданных StepSecurity показывает, почему это было важно: легитимные релизы уже содержали аттестации происхождения, и 2.3.0 был исключением, опубликованным с учётной записи человека. Проблема заключалась в том, что путь через долгоживущий токен оставался открытым наряду с доверенной публикацией, и именно это Endor Labs призывает мейнтейнеров закрыть. Cline опубликовал GHSA-9ppg-jx86-fqw7, пометил 2.3.0 как устаревшую с сообщением о том, что её не следует устанавливать, и направил пользователей на 2.4.0 или более позднюю версию.

Структурные рекомендации Хана идут дальше того, что было реализовано, и их стоит зафиксировать как его собственные, а не как рекомендации Cline: убрать Bash, Write и Edit из любого workflow триажа, оставив ему только чтение файлов и те конкретные вызовы GitHub CLI, которые ему нужны; никогда не восстанавливать кэш в задании, которое держит секреты публикации продакшена; и дать ночным релизам собственное пространство имён реестра и выделенную непродакшен-идентичность для публикации, чтобы украденный токен ночного релиза вообще не мог опубликовать стабильный релиз.

Восьмидневный разрыв между исправлением и вредоносной публикацией — это та деталь, из-за которой эту запись стоит сохранить. Каждый шаг в цепочке был известной техникой; Хан опубликовал инструмент отравления кэша, а исследование PromptPwnd компании Aikido Security за декабрь 2025 года задокументировало тот же паттерн неправильной конфигурации триажа. В инцидент с цепочкой поставок их превратил рабочий процесс, позволявший тексту постороннего человека попадать в оболочку, кэш, общий с задачами, владевшими ключами выпуска, и ротация токенов, пропустившая одни учётные данные. Каждое из трёх исправлений само по себе разорвало бы цепочку; третье пришло на восемь дней позже.

© 2026 OrcaRouter