Centralized scanner to detect suspicious npm lifecycle scripts and known malicious packages (like the Shai‑Hulud worm) across all repositories of a GitHub user.
This repository contains a small toolset that:
- scans all repositories of a given GitHub user via the GitHub API;
- finds
package.jsonfiles; - looks for:
- dangerous lifecycle scripts (
preinstall,install,postinstall,prepare); - dependencies from a configurable blocklist (e.g. known malicious or typosquatted packages);
- dangerous lifecycle scripts (
- produces a summary report.
The primary goal is to reduce the risk of npm supply‑chain attacks, especially those that hide in lifecycle scripts and try to steal tokens, SSH keys, or other secrets during npm install.
- A GitHub Actions workflow runs on a schedule or on demand.
- It uses a fine‑grained Personal Access Token (PAT) from GitHub Secrets to:
- list all repositories of the target user;
- read
package.jsonfiles via the GitHub API (no full clone).
- A Node.js script:
- parses each
package.json; - checks the
scriptssection for risky lifecycle hooks; - checks dependencies against a JSON blocklist (known compromised/suspicious packages);
- logs findings and writes a JSON report.
- parses each
The scanner is read‑only: it does not modify repositories and does not push any changes.
- Node.js (for local development / running the scanner script).
- A GitHub fine‑grained PAT with:
- Contents: Read permission;
- access to repositories you want to scan.
The PAT is injected into workflows via a secret named, for example, GH_PAT_SH_SCAN.
The repository includes a workflow that:
- runs on a schedule (e.g. daily) or manually;
- uses
secrets.GH_PAT_SH_SCANto authenticate; - runs the central scan script;
- stores/prints a brief summary of findings.
Example environment usage in a workflow:
env:
GH_PAT_SH_SCAN: ${{ secrets.GH_PAT_SH_SCAN }}
TARGET_USER: des-yogiYou can also run the scanner locally (exact command may differ depending on the final script name):
node central-scan.jsBefore running locally, export your PAT as an environment variable:
export GH_PAT_SH_SCAN=github_pat_...The script will:
- query your repositories via GitHub API;
- scan
package.jsonfiles; - print a summary (and optionally write a JSON report).
In each package.json, these keys are inspected:
preinstallinstallpostinstallprepare
Any non‑trivial code in these hooks can be a potential red flag, especially when it:
- sends HTTP requests,
- reads files from
~/.sshor other sensitive locations, - executes downloaded binaries.
The scanner does not automatically classify scripts as malicious; it highlights them for manual review.
The scanner maintains a JSON list of packages that should never appear in dependencies, for example:
shai-hulud@shai-hulud/core- suspicious typosquats like
lodash-ts-fixer
If such a package is found in:
dependenciesdevDependenciespeerDependenciesoptionalDependencies
it will be reported as a critical finding.
- The PAT used by the scanner has read‑only access and is stored only in GitHub Secrets, not in the repository.
- The scanner never writes to scanned repositories.
- If a secret ever leaks, you can rotate it by:
- generating a new fine‑grained PAT;
- updating the corresponding GitHub secret;
- re‑running the workflow.
See UPDATE_TOKEN_MANUAL.md in this repository for a detailed step‑by‑step guide on rotating the token.
- Per‑repository GitHub Actions workflow for on‑push scans.
- E‑mail / issue notifications when suspicious scripts or packages are found.
- White‑list mode for very stable stacks: warn on any new dependency not present in a trusted baseline.
- Optional integration with SCA tools (Snyk, etc.) for known vulnerabilities.
This code is completely free to use, modify and distribute without any restrictions.
Disclaimer:
The software is provided “as is”, without warranty of any kind, express or implied.
The author is not responsible for any damage, data loss, security incidents or other consequences that may arise from using this code, whether directly or indirectly.
Центральний сканер, який шукає підозрілі npm‑lifecycle‑скрипти та відомі шкідливі пакети (наприклад, черв’як Shai‑Hulud) у всіх репозиторіях користувача GitHub.
Цей репозиторій містить невеликий набір інструментів, який:
- сканує всі репозиторії вказаного користувача GitHub через GitHub API;
- знаходить файли
package.json; - шукає:
- небезпечні lifecycle‑скрипти (
preinstall,install,postinstall,prepare); - залежності з налаштовуваного чорного списку (наприклад, відомі шкідливі або typosquat‑пакети);
- небезпечні lifecycle‑скрипти (
- формує зведений звіт.
Основна мета — зменшити ризик supply‑chain атак в npm, особливо тих, що ховаються в lifecycle‑скриптах і намагаються вкрасти токени, SSH‑ключі чи інші секрети під час npm install.
- Workflow GitHub Actions запускається за розкладом або вручну.
- Він використовує fine‑grained Personal Access Token (PAT) з GitHub Secrets, щоб:
- отримати список усіх репозиторіїв цільового користувача;
- прочитати файли
package.jsonчерез GitHub API (без повного клонування).
- Node.js‑скрипт:
- парсить кожен
package.json; - перевіряє секцію
scriptsна наявність ризикових lifecycle‑хуків; - перевіряє залежності за JSON‑чорним списком (відомі скомпрометовані/підозрілі пакети);
- логувує знахідки та записує JSON‑звіт.
- парсить кожен
Сканер працює лише в режимі read‑only: він не змінює репозиторії й нічого не пушить.
- Node.js (для локального запуску скриптів).
- GitHub fine‑grained PAT з правами:
- Contents: Read;
- доступом до репозиторіїв, які потрібно сканувати.
PAT передається у workflow через секрет, наприклад GH_PAT_SH_SCAN.
У репозиторії є workflow, який:
- виконується за розкладом або вручну;
- використовує
secrets.GH_PAT_SH_SCANдля автентифікації; - запускає центральний скан;
- виводить короткий підсумок і за потреби зберігає звіт.
Приклад використання змінних оточення у workflow:
env:
GH_PAT_SH_SCAN: ${{ secrets.GH_PAT_SH_SCAN }}
TARGET_USER: des-yogiСканер можна запустити і локально (точна команда залежить від назви фінального скрипта), наприклад:
node central-scan.jsПеред запуском локально потрібно експортувати PAT у змінну оточення:
export GH_PAT_SH_SCAN=github_pat_...Скрипт:
- отримає список репозиторіїв через GitHub API;
- просканує файли
package.json; - виведе підсумок (і, за потреби, збереже JSON‑звіт).
У кожному package.json перевіряються такі ключі:
preinstallinstallpostinstallprepare
Будь‑який нетривіальний код у цих хуках може бути підозрілим, особливо якщо він:
- робить HTTP‑запити,
- читає файли з
~/.sshчи інших чутливих місць, - виконує завантажені бінарники.
Сканер не визначає автоматично, що скрипт шкідливий; він підсвічує важливі місця для ручного перегляду.
Сканер тримає JSON‑список пакетів, яких не повинно бути у залежностях, наприклад:
shai-hulud@shai-hulud/core- підозрілі typosquat‑пакети на кшталт
lodash-ts-fixer
Якщо такий пакет знайдений у:
dependenciesdevDependenciespeerDependenciesoptionalDependencies
— він потрапляє в звіт як критична знахідка.
- PAT для сканера має лише read‑only‑доступ і зберігається тільки в GitHub Secrets, а не в репозиторії.
- Сканер ніколи не записує нічого в цільові репозиторії.
- Якщо PAT колись скомпрометують, його можна легко замінити:
- створити новий fine‑grained PAT;
- оновити відповідний GitHub Secret;
- перезапустити workflow.
Детальний покроковий гайд з ротації токена — у файлі UPDATE_TOKEN_MANUAL.md в цьому репозиторії.
- Пер‑репозиторні GitHub Actions, які запускають скан при кожному push.
- Сповіщення (e‑mail / issue), коли знайдені підозрілі скрипти або пакети.
- Режим білого списку для дуже стабільних стеків: попереджати про будь‑яку нову залежність, якої немає в довіреній базі.
- Опційна інтеграція з SCA‑інструментами (Snyk тощо) для пошуку відомих вразливостей.
Цей код повністю вільний для використання, зміни та розповсюдження без будь‑яких обмежень.
Відмова від відповідальності:
Програмне забезпечення надається «як є», без будь‑яких гарантій, явних чи неявних.
Автор не несе відповідальності за будь‑які пошкодження, втрату даних, інциденти безпеки чи інші наслідки, що можуть виникнути в результаті використання цього коду — як безпосередньо, так і опосередковано.