Исследователи Radware Габи Накибли и Цвика Бабо искали prompt-инъекции на GitHub, а нашли скоординированную кампанию против CI/CD. За ней, по их оценке, стоит один человек. Он использовал 74 аккаунта, по всей видимости взломанных: у многих была настоящая история разработки.
Как это работало
1 сентября за 43 минуты появилось 77 вредоносных issues, PR и комментариев, ещё шесть — в следующие две минуты. Всего на 13 октября насчитали 83 объекта в 61 публичном репозитории. Среди целей — agno, ToolJet, google/langextract, aquasecurity/trivy, CopilotKit, podman, mlflow, brave-browser, Homebrew/homebrew-cask и PX4-Autopilot.
Команда пряталась в HTML-комментарии: на странице её не видно. Новое issue или PR запускает workflow, подписанный на это событие. Если workflow подставляет текст из события прямо в shell-скрипт, команда выполняется. Она собирала переменные окружения и пыталась отправить их на сервер атакующего. Доступ к репозиторию не нужен, хватает обычного аккаунта GitHub.
Итог
В двух случаях логи подтверждают, что команда выполнилась. Получил ли атакующий права на запись или изменил код, установить не удалось. Мейнтейнеров уведомили, большинство проектов уязвимость закрыли.
Что делать
- Не подставлять
${{ github.event.issue.body }}и подобные поля прямо вrun:. Передавать их через переменные окружения. - Отделять задачи на внешние события от задач с секретами и правами на запись.
- Урезать
permissionsи набор секретов, доступных workflow.
Radware researchers Gabi Nakibly and Zvika Babo were looking for prompt injection on GitHub and found a coordinated campaign against CI/CD. They believe one person ran it using 74 accounts that were probably compromised, since many had genuine development histories.
How it worked
On 1 September, 77 malicious issues, PRs and comments appeared within 43 minutes, plus six more over the next two minutes. As of 13 October the count was 83 items across 61 public repositories, including agno, ToolJet, google/langextract, aquasecurity/trivy, CopilotKit, podman, mlflow, brave-browser, Homebrew/homebrew-cask and PX4-Autopilot.
The command sat inside an HTML comment, invisible on the rendered page. A new issue or PR triggers any workflow listening for that event, and if the workflow splices event text straight into a shell script, the command runs. It collected environment variables and tried to send them to an attacker server. No repository access is needed, just an ordinary GitHub account.
Outcome
Logs confirm execution in two cases. The researchers could not determine whether the attacker gained write access or altered code. Maintainers were notified and most projects have fixed their workflows.
What to do
- Never interpolate
${{ github.event.issue.body }}and similar fields directly intorun:; pass them through environment variables. - Keep jobs triggered by external events apart from jobs holding secrets or write permissions.
- Trim
permissionsand the set of secrets available to workflows.