Packj: Auditing Package Risk Before You Install
Packj stops :zap: Solarwinds-, ESLint-, and PyTorch-like attacks by flagging malicious/vulnerable open-source dependencies ("weak links") in your software supply-chain
At a glance
- What is it?
- Packj is a Python tool that vets npm, PyPI, RubyGems and other registry packages for risky attributes and can install them under strace. It is beta software with an AGPL-3.0 licence, and its value depends on how much you trust its rule-based heuristics.
- Who is it for?
- Adopt Packj if you want a second opinion on package metadata and install-time behaviour before a dependency reaches production, and you can run it in Docker or as a GitHub Action without touching your main build. Do not adopt it if you need a stable, versioned tool: the latest release is v0.15-beta from February 2023, and the README itself carries a beta badge.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap Packj targets: CVE scanners assume the code is benign
Packj's README makes a direct argument against the tools most teams already run. Existing CVE scanners, it says, ASSUME code is BENIGN and do not analyze its behavior. That is the gap Packj claims to fill. A CVE scanner answers whether a known vulnerability has been disclosed against a package version. It does not answer whether the package's author email domain has expired, whether the release history has a suspicious gap, whether the package requests sensitive APIs, or whether the install script does something unexpected. Packj audits for those attributes and labels them risky. The intended audience is engineers and security reviewers who already have CVE scanning in place and want a second layer focused on package metadata and install-time behaviour. It is not a replacement for a vulnerability database, and the README does not present it as one.
Two modes: static audit and strace-based install tracing
The tool ships two functions. The audit command vets a package for risky attributes. The sandbox function is for safe installation of a package. By default, audit performs static code analysis only. Passing -t or --trace switches on dynamic analysis, which installs the requested packages under strace and monitors install-time behaviour. The example in the README runs the Docker image with audit --trace -p npm:browserify and shows a line-by-line checklist: package description, release history, version age, release time gap, author, email and domain validity, readme size, homepage, download counts, repository URL, repository data, whether the repo is a forked copy, repository activity, and CVEs. Some lines pass, some are marked RISK. In that example the version is flagged as 702 days old and the author email domain is flagged as expired. This is the mechanism in plain terms: Packj fetches registry metadata, runs a set of named checks against it, and prints PASS or RISK per check. The trace mode adds observed install behaviour on top of that.
Supported registries, and the ones marked unsupported
The README lists NPM, PyPI, Cargo, RubyGems, Packagist, Nuget and Maven as supported, with Rust and PHP support described as work in progress even though Cargo and Packagist appear in the table. Docker and Cocoapods are marked unsupported. Packj can also vet local, unpublished NPM and PyPI packages, which matters if you build internal packages and want the same checks applied before publication. The practical constraint here is coverage: if your stack is .NET or Java, the table says supported, but the README gives no worked example for either, so the depth of those checks is not something you can confirm from the documentation alone. For npm, PyPI and RubyGems the examples are concrete and the behaviour is described in more detail.
Getting it running: Docker, GitHub Action, or source
The README recommends Docker as the quickest way to try Packj. The command is docker run -v /tmp:/tmp/packj -it ossillate/packj:latest --help, and Podman is also supported for containerized runs. The GitHub Action is used as a step named Packj Security Audit, pointing at ossillate-inc/packj-github-action@v0.0.10-beta, with two inputs: DEPENDENCY_FILES and REPO_TOKEN. The README's example sets DEPENDENCY_FILES to pypi:requirements.txt,npm:package.json,rubygems:Gemfile and REPO_TOKEN to the workflow's GITHUB_TOKEN. Note the format: each entry is registry:path, comma-separated. For source installs, clone the repository, run bundle install && pip3 install -r requirements.txt, then python3 main.py --help. Auditing accepts either explicit packages (python3 main.py audit -p pypi:requests rubygems:overcommit) or dependency files (python3 main.py audit -f npm:package.json pypi:requirements.txt). The same registry:name prefix convention applies in both forms.
Customisation is the answer to alert noise
A tool that flags expired email domains and stale versions will produce findings that many teams will not care about. Packj's README addresses this under Customization, describing the ability to turn off alerts as per your threat model to reduce noise. That is the right design instinct, but the README does not spell out the configuration keys or file format in the material available here, and v0.15-beta is described only as Rules and placeholder for more upcoming checks. So the tuning surface exists but its shape is not documented in what I can see. Treat that as the first thing to investigate before you wire Packj into a pull request gate: an alert you cannot silence is an alert your team will learn to ignore, and the README's own framing suggests the authors know this.
Beta status, release cadence, and what that costs you
The release history is short and old relative to the repository's last push. v0.15-beta landed on 2023-02-01, v0.14-beta on 2023-01-26, and v0.13-beta on 2022-12-08. The README carries a beta badge and a note that a self-hosted Packj webserver and several integrations are coming later this month, a note that reads as stale given the release dates. The GitHub Action is pinned at v0.0.10-beta. For an operator, this means no stable release line to track and no long-term support signal in the material. The project began as a PhD research project and the README states it is currently being developed under various govt grants, which explains the research orientation but does not promise production support. Upgrade cost is therefore not a versioned migration problem so much as an availability problem: you are tracking a beta tool whose check set is still being filled in.
Licence: AGPL-3.0 and what it implies for internal use
Packj is licensed AGPL-3.0. That is a strong copyleft licence, and it is the single most consequential fact for anyone thinking about embedding Packj in a product or offering it as a service. AGPL-3.0's network clause is the part that catches teams off guard: running modified software over a network can trigger source distribution obligations. Running the Docker image or the GitHub Action as a standalone audit step inside your own CI is a different situation from linking Packj into something you ship or exposing a modified version as a service. I am not a lawyer and this is not legal advice. If your organisation has a policy on AGPL, run Packj past whoever owns that policy before it becomes part of a build pipeline, not after.
Where Packj is the wrong tool, and what to use instead
Packj is the wrong tool when you need deterministic, reproducible pass/fail results in a release gate. Its checks are heuristic and metadata-driven, and the README's own example shows a widely used package (browserify, 2M weekly downloads, 484 versions, 2290 commits) flagged RISK on version age and email domain validity. Those findings may be exactly what you want, or they may be noise that blocks a merge for reasons unrelated to security. A real alternative in the same space is Dependabot, which GitHub ships natively. The approaches differ fundamentally: Dependabot watches your manifest files, opens pull requests when a dependency has a newer version, and surfaces known advisories from a vulnerability database. It reasons about versions and advisories, not about author email domains, release time gaps, or install-time syscalls. Packj reasons about package risk signals and observed install behaviour, and does not manage your dependency versions for you. If what you need is automated updates and advisory alerts, Dependabot covers it with no new infrastructure. If what you need is a behavioural and metadata risk opinion before installation, that is the space Packj occupies, and it comes with the beta caveats above.
Editorial conclusion
Adopt Packj if you want a second opinion on package metadata and install-time behaviour before a dependency reaches production, and you can run it in Docker or as a GitHub Action without touching your main build. Do not adopt it if you need a stable, versioned tool: the latest release is v0.15-beta from February 2023, and the README itself carries a beta badge. Before you commit, run the Docker image against your own dependency files, read the alert output for false positives, and check which of the supported registries your project actually uses.
Community notes