В LinkedIn пришло сообщение от рекрутера из небольшого криптостартапа. После пары дней переписки она описала сломанный proof-of-concept, для которого искали ведущего инженера, и прислала публичный GitHub-репозиторий. Попросила «проверить проблему с устаревшими модулями Node».
Что-то показалось подозрительным. Автор не стал клонировать и устанавливать зависимости. Вместо этого он поднял временный VPS на Hetzner, склонировал репозиторий туда и запустил Pi в read-only режиме, разрешив только инструменты для чтения файлов. Pi быстро остановился на файле app/test/index.js.
Внутри было около 250 строк, замаскированных под тесты. Там собирался URL: https://rest-icon-handler.store/icons/77. Среди стен закомментированных тестов пряталась команда, которая выполняла всё, что пришлёт сервер обратно на машину жертвы.
Срабатывало это без запуска тестов. app/index.js делал require('./test'), загружая и выполняя app/test/index.js. А package.json привязывал app/index.js к запуску через скрипт prepare. npm запускает prepare автоматически после npm install. Так что установка зависимостей уже активировала бэкдор. Просьба «проверить модули Node» была приманкой, чтобы жертва запустила npm install.
Коммиты в репозитории были подписаны именем и почтой реального разработчика — с полноценным LinkedIn, сайтом и историей на GitHub. Автор написал ему под видом коллеги, унаследовавшего код. Тот ответил, что никогда не работал на эту компанию, его личность уже подделывали раньше, и он сам отправляет жалобы на такие репозитории. Все 39 коммитов принадлежали человеку, который к ним не прикасался.
Профиль рекрутера тоже оказался подделкой. Его украли у известного arts-журналиста без технического бэкграунда. Когда автор притворился, что не может запустить проект, «журналист» мгновенно превратился в эксперта по версиям Node и убеждал запустить npm install.
Автор признаёт: в уставший день можно было попасться. Он советует при получении ссылок на репозитории через LinkedIn проявлять паранойю и соблюдать гигиену безопасности. Проверка кода read-only агентом сработала быстрее и точнее, чем ручной просмотр — бэкдор был замаскирован под неряшливый код новичка. Репозиторий отправлен в жалобу GitHub, рекрутер — в LinkedIn. Пока ничего не изменилось, код всё ещё доступен.