Skip to content
 
 

Repository files navigation

Node Package Scanner

🛡️ Enterprise-grade GitHub Action and CLI tool to detect compromised packages from the Shai Hulud supply chain attack

This tool scans your JavaScript projects for compromised packages identified in the ongoing Shai Hulud supply chain attack targeting npm packages that impersonate CrowdStrike fixes.

Features

  • Dual Purpose: Works as both GitHub Action and standalone CLI tool
  • 🔍 Multi-Package Manager Support: Scans npm, Yarn, and pnpm lock files
  • 💾 Smart Caching: Falls back to cached lists when remote fetch fails
  • ⚙️ Configurable: YAML configuration with sensible defaults
  • 🚨 GitHub Integration: Automatically comments on PRs and fails CI checks
  • 🏢 Enterprise Ready: Suitable for air-gapped environments

Quick Start

GitHub Action (Marketplace)

This action is available in the GitHub Actions Marketplace. Add it to your workflow (.github/workflows/security-scan.yml):

name: Security Scan
on: [push, pull_request]

jobs:
  shai-hulud-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: drewpayment/node-pkg-scanner@v1
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

The action will automatically:

  • Scan your repository for compromised packages
  • Comment on pull requests if issues are found
  • Fail the CI check when compromised packages are detected
  • Support npm, Yarn, and pnpm projects

CLI Usage (Clone Repository)

Clone and use this tool directly with Bun for local scanning:

Prerequisites

First, install Bun if you haven't already:

curl -fsSL https://bun.sh/install | bash

Or visit bun.sh for alternative installation methods.

Installation & Usage

# Clone the repository
git clone https://github.com/drewpayment/node-pkg-scanner.git
cd node-pkg-scanner

# Install dependencies
bun install

# Run the scanner
bun run cli scan

# Scan with custom config
bun run cli scan --config ./custom-config.yml

# Scan specific directory
bun run cli scan --directory ./my-project

# Scan without failing on detection (for reporting only)
bun run cli scan --no-fail

Standalone Binary (No Dependencies)

For teams that want to use the scanner without installing Node.js, npm, or Bun, you can use the pre-compiled standalone binaries:

Building Binaries

Option 1: Multi-platform build (Development/Testing)

# Clone the repository and build all binaries from one machine
git clone https://github.com/drewpayment/node-pkg-scanner.git
cd node-pkg-scanner
bun install
bun run build:binaries

Option 2: Native platform builds (Production - Recommended)

# On each target platform, run:
bun run build:binary

For production distribution, use Option 2 for best compatibility:

  • Run bun run build:binary on macOS → Creates node-pkg-scanner-macos
  • Run bun run build:binary on Windows → Creates node-pkg-scanner-windows.exe
  • Run bun run build:binary on Linux → Creates node-pkg-scanner-linux

This creates platform-specific binaries with optimal compatibility.

Preinstall Hook Usage

The most powerful use case is integrating the scanner into npm's preinstall hook to prevent compromised packages from being installed:

Step 1: Place the appropriate binary in your project (e.g., in a security/ directory)

Step 2: Add to your package.json:

{
  "scripts": {
    "preinstall": "./security/node-pkg-scanner-macos scan --quiet || (echo '❌ Security scan failed - aborting install' && exit 1)"
  }
}

Step 3: Make executable (Mac/Linux):

chmod +x security/node-pkg-scanner-macos

Now every time someone runs npm install, yarn install, or pnpm install, the scanner will run first and prevent installation if compromised packages are detected.

See the examples/ directory for platform-specific package.json examples and advanced configurations.

Configuration

# Path to the configuration file
configPath: .config.yml
Create a `.config.yml` file in your repository root:

```yaml
# Severity level for compromised packages (error, warning, info)
severityLevel: error

# URL to fetch the compromised packages list from
compromisedPackagesUrl: https://raw.githubusercontent.com/Cobenian/shai-hulud-detect/main/compromised-packages.txt

# Root directory to scan (optional - defaults to current directory)
# rootDirectory: ./src

# Additional packages to check for (beyond the remote list)
additionalPackages: []
  # - suspicious-package-name

# Directories to exclude from scanning
excludeDirectories:
  - node_modules
  - .git
  - dist
  - build

# Cache timeout in minutes
cacheTimeout: 60

GitHub Action Inputs

Input Description Default
config-path Path to configuration file .config.yml
fail-on-error Fail the action when compromised packages found true
github-token GitHub token for API access ${{ github.token }}

GitHub Action Outputs

Output Description
compromised-found Whether any compromised packages were found (true/false)
compromised-count Number of compromised packages found
compromised-packages JSON array of compromised packages found

CLI Usage

Scan Command

# Basic scan
bun run cli scan

# Scan with custom config
bun run cli scan --config ./custom-config.yml

# Scan specific directory
bun run cli scan --directory ./my-project

# Scan without failing on detection (for reporting only)
bun run cli scan --no-fail

# Quiet mode (minimal output)
bun run cli scan --quiet

Binary Usage

# Using standalone binary (no dependencies required)
./security/node-pkg-scanner-macos scan
./security/node-pkg-scanner-windows.exe scan  # Windows
./security/node-pkg-scanner-linux scan        # Linux

# All the same options are available
./security/node-pkg-scanner-macos scan --config custom-config.yml --quiet

Initialize Configuration

# Create default config file
bun run cli init

# Overwrite existing config
bun run cli init --force

Advanced Usage

Custom Package Lists

You can provide your own compromised packages list by setting a custom URL in the configuration:

compromisedPackagesUrl: https://your-domain.com/compromised-packages.txt

The file should be a simple text file with one package name per line:

malicious-package-1
suspicious-package-2
fake-crowdstrike-fix

Branch Protection Rules

To block PRs automatically, configure branch protection rules in your GitHub repository:

1. Go to Settings → Branches
2. Add or edit a branch protection rule
3. Check "Require status checks to pass before merging"
4. Add "Node Package Scanner" to required status checks

### Azure DevOps / Other CI Platforms

Use the CLI tool in any CI/CD platform:

```yaml
# Azure DevOps example (Bun with repo clone)
- script: |
    curl -fsSL https://bun.sh/install | bash
    git clone https://github.com/drewpayment/node-pkg-scanner.git scanner
    cd scanner && bun install
    bun run cli scan --directory ../
  displayName: 'Scan for compromised packages'
# GitLab CI example (Bun with repo clone)
security-scan:
  image: oven/bun:latest
  script:
    - git clone https://github.com/drewpayment/node-pkg-scanner.git scanner
    - cd scanner && bun install
    - bun run cli scan --directory ../

Package Manager Support

Package Manager Files Scanned
npm package.json, package-lock.json
Yarn package.json, yarn.lock
pnpm package.json, pnpm-lock.yaml

Caching Behavior

  1. Primary: Attempts to fetch latest compromised packages from remote URL
  2. Fallback: Uses cached version if remote fetch fails and cache is valid
  3. Last Resort: Uses embedded fallback list if no cache available

Cache is stored in system temp directory and respects the cacheTimeout configuration.

Security Considerations

  • No Credentials Required: Uses public package registries and GitHub APIs
  • Minimal Permissions: Only requires basic repository read access
  • Offline Capable: Works in air-gapped environments with cached lists
  • Audit Trail: All actions are logged and trackable

Troubleshooting

Common Issues

"Failed to fetch compromised packages list"

  • Check internet connectivity
  • Verify the URL is accessible
  • Check if cached version exists and is valid

"No package files found"

  • Verify you're in the correct directory
  • Check excludeDirectories configuration
  • Ensure package manager files exist

"GitHub API rate limiting"

  • Provide a GitHub token with appropriate permissions
  • Use the tool less frequently or implement caching

Debug Mode

Enable verbose logging by setting the DEBUG environment variable:

# With npm global install
DEBUG=node-pkg-scanner* node-pkg-scanner scan

# With Bun (cloned repository)
DEBUG=node-pkg-scanner* bun run cli scan

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

Security Disclosure

If you discover a security vulnerability, please send an email to security@your-org.com instead of using the issue tracker.

References


⚠️ Important: This tool helps detect known compromised packages but should be part of a comprehensive security strategy. Always keep your dependencies updated and monitor security advisories.

About

Compromised Node package scanner to scan for Shai Hulud compromised packages from CLI or from GitHub Actions. Additionally, this tool can be configured to work for other compromised packages beyond the Shai Hulud npm supply chain attack.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages