A security tool that scans your project's dependencies to identify packages that were published too recently, helping protect against supply chain attacks and malicious package uploads.
This tool is proudly developed and maintained by the engineering team at Moneytree KK, a leading Tokyo-based financial technology company. Our core mission is founded on the principles of Privacy by Design and data integrity, adhering to stringent security standards like ISO 27001. We released this utility in response to the rise of software supply chain attacks, aiming to contribute our expertise back to the open-source community and help developers everywhere secure their supply chains.
Supply Chain Guard analyzes manifest files (eg. lockfiles) in your repository and checks if any packages were published within a specified time window (default: 10 days). This helps detect potentially malicious packages that may have been uploaded recently as part of supply chain attacks.
The tool currently supports the following manifest files:
- Bundler (Ruby)
- NPM (JavaScript, TypeScript)
- Pip (Python)
- SPM (Swift)
- Yarn (JavaScript, TypeScript)
And the following registries:
- GitHub packages
- GitHub repositories
- NPM (JavaScript, TypeScript)
- PyPI (Python)
- RubyGems (Ruby)
- Node.js ≥ 24.0.0
- Git repository (uses
git ls-filesfor discovery)
This is an internal Moneytree tool published to GitHub Packages. You have several options to install and run it:
npx @moneytree/supply-chain-guardnpm install -g @moneytree/supply-chain-guard
supply-chain-guardRun the tool from your project directory. It will scan all supported manifest files in your repository and flag any packages published within the last 10 days.
Typically, you'll want to run Supply Chain Guard from CI, whenever somebody makes a pull request.
Some things to keep in mind:
- Make sure to use a compatible Node.js version in your environment (≥ 24.0.0).
- Use
--diffto limit scans to changed manifest files only. This will save time and reduce load on the registries that need to be queried. - If you have dependencies that are hosted on GitHub, set
GITHUB_TOKENfor calls to the GitHub API.
--max-release-days-ago <days>- Set the maximum age threshold in days (default: 10)--concurrency <number>- Number of concurrent API requests (default: 20)--diff <branch>- Only include manifest files that differ from this branch--verboseor-v- Enable verbose output-vv- Enable very verbose output (extra detailed logging)--forceor-f- Check packages even from manifest files not recently modified
# Check for packages published in the last 7 days
supply-chain-guard --max-release-days-ago 7
# Use higher concurrency for faster scanning
supply-chain-guard --concurrency 50
# Verbose output to see detailed scanning information
supply-chain-guard --verbose
# Force check even for older manifest files
supply-chain-guard --force
# Very verbose output with extra details
supply-chain-guard -vv
# Combine options
supply-chain-guard --max-release-days-ago 3 --concurrency 30 --verbose --force0- Success: No recently published packages found1- Error: Recently published packages detected2- Error: Unexpected error occurred3- Error: Invalid command line arguments
You can create allow lists to exempt specific packages from scanning. This is useful for hotfix releases that you want to adopt specifically because they address a security issue.
Create a .supply-chain-guard-allow.json file in your project directory:
{
"npm": {
"package-name": ["1.2.3", "1.2.4"],
"@scoped/package": ["4.5.6"]
},
"pypi": {
"some-python-package": ["0.1.2"]
},
"rubygems": {
"some-ruby-gem": ["3.2.1"]
},
"githubRepositories": {
"some-org/some-repo": ["commit:723fa5a6c65812aec4a0d7cc432ee198883b6e00"]
},
"githubPackages": {
"some-org/some-package": ["npm:1.2.3"]
}
}Wildcards (*) are allowed in place of:
- packages:
"npm": "*", allowing everything in the registry (not normally advisable -- an exception could be when the registry is down and you absolutely must get CI to pass). - package name after scope:
"moneytree/*": "*", allowing all packages owned by the organization owning this scope. - versions:
"@moneytree/eslint-config": "*", allowing this package, regardless of its version.
For example, to allow all packages authored by Moneytree itself, you can set up this .supply-chain-guard-allow.json file in your project root:
{
"npm": {
"@moneytree/*": "*"
},
"githubRepositories": {
"moneytree/*": "*"
},
"githubPackages": {
"moneytree/*": "*"
}
}You can place allow list files in subdirectories to create directory-specific exemptions. The tool will apply allow lists based on the location of the manifest file being scanned.
- Discovery: Scans the repository using
git ls-filesto find all supported manifest files - Filtering: Skips manifest files that haven't been modified within the threshold period (unless
--forceis used) - Allow List: Checks for and applies directory-specific allow lists for exempted packages
- Parsing: Extracts package information from manifest files for each supported ecosystem
- Validation: Queries package registries to get publication dates with configurable concurrency
- Analysis: Compares publication dates against the specified threshold
- Reporting: Reports any packages that breach the age threshold
"No parser found for manifest file": The tool encountered a manifest file it doesn't recognize. This usually means support for that package system needs to be added.
HTTP errors: Use --concurrency with a lower value to reduce concurrent requests to package registries.
Manifest files being skipped: By default, the tool only checks manifest files that have been modified within the threshold period. Use --force to check all manifest files regardless of modification time.
Read developer documentation in DEVELOPMENT.md.
See SECURITY.md for information on how to responsibly disclose security vulnerabilities.