Navigation
Open source · Apache-2.0 · v2.7.2

Catch a supply-chain attack before it ships.

postmortem reads the code you install and the history of who publishes it. Malicious install scripts, typosquats, hijacked maintainer accounts, all flagged before your build runs them. One binary, offline by default.

postmortem scan .

            
real output, postmortem 2.7.2offline
8/ 11
real supply-chain attacks replayed, 8 raise a signal
82days
of warning on event-stream before npm pulled it
8/ 9
known typosquats caught, offline, across npm, PyPI and crates.io
11.3s
to scan npx n8n: 1,975 packages, 2.9 GB, on 2 vCPU
Case 01

The attack was visible before the payload.

In 2018 an attacker asked the maintainer of event-stream for publish rights, got them, and shipped a harmless release to look legitimate. That release is the tell: a new publisher, after 779 days of silence. postmortem flags it from the registry history alone, no malware signature needed.

npm · event-stream · Sep to Nov 2018
82 days flagged before removal
dates from npm's incident report
779 days quiet
postmortem already shows the release as suspicious
2011-11-01
0.5.2
first release
5 SEP 2018
3.3.5 · new publisher
dominictarr → right9ctrl
flagged from here: new-publisher, dormant-release (779d)
9 SEP 2018
3.3.6
pulls in flatmap-stream
26 NOV 2018
npm removes it
after public report
$ postmortem timeline event-stream
  2018-09-05 ! 3.3.5   publisher changed  dominictarr → right9ctrl
                       released after 779d of silence
  2018-09-09 ! 3.3.6   unpublished
Read all 11 replays, misses included →
Findings

A CVE scanner finds bugs. This finds intent.

Two examinations on every dependency: what its code does when you install it, and what changed in the way it gets published.

In the code

postmortem scan · fully offline
install_hook
Install-time scripts that reach for the network or a shell, before you ever import the package.
npm `postinstall` script defined, references network/exec primitives
obfuscation
Packed eval, Function() constructors, char-code reassembly, high-entropy blobs.
5 obfuscation signal(s): eval(), base64 blob (entropy 5.41)
ioc
URLs, IPs, domains and checksum-validated crypto wallets hidden in library code.
Bitcoin address, extremely unusual in dependency code
sensitive_api
Process spawning and outbound calls where a library has no business making them.
uses child_process, require('https')
ghost
npm tarballs that do not match the source commit they claim to be built from.
234 versions compared on n8n, 1 ghost found

In the history

postmortem tree --online · registry metadata only
new-publisher
Someone new is shipping releases of a package you already trust.
publisher changed dominictarr → right9ctrl
dormant-release
A release after years of silence, the classic sign of a takeover.
released after 779d of silence
provenance-removed
The previous versions came from trusted CI, this one came from a laptop or a stolen token.
nx 2025, axios 2026
typosquat
Names one keystroke from a popular package, plus starjacking of its GitHub stars.
typosquat of lodash (transposed), starjacking
install-script-added
A package that never ran code at install suddenly does, often alongside a fresh release.
Shai-Hulud 2025: node bundle.js
Toolkit

One binary. Every question about your dependencies.

Each subcommand answers one question, and every one of them speaks JSON for your scripts.

scan

Malicious code in what you install, or inside a container image. SARIF and HTML reports.

tree --online

The dependency graph with reputation and provenance. --human shows who controls what.

audit

One graded verdict covering malware, risk and CVEs.

timeline <pkg>

Publisher handovers, install scripts appearing, repository moves, unpublished versions.

hunt

An attack is announced: were you ever exposed, where, and since which commit?

diff

What a branch or a GitHub pull request adds to your dependency tree.

why --blast

Why a package is installed, and what a compromise of it would reach.

scripts

Every dependency that runs code at install time, approved or pending.

system

The same audit for the packages installed on the machine itself.

fix

The smallest upgrade that clears the known CVEs.

licenses · sbom

License policy with allow and deny lists, CycloneDX 1.5 export.

hook · watch

A git pre-commit hook, or a re-scan each time a lockfile changes.

Coverage

Your lockfiles, and the machine they run on.

Point it at a project folder and it finds every lockfile on its own. Point system at a laptop or a server and it reads what the package managers installed.

Dependencies

Seven ecosystems, plus sources

JavaScript
npm · pnpm · Yarn
Python
Poetry · Pipenv · uv · requirements
Rust
Cargo.lock
Go
go.mod · go.sum
Ruby
Gemfile.lock
PHP
composer.lock
Java
pom.xml · Gradle
C, C++, Perl
source scan
Operating systems

Linux, macOS, Windows

Debian, Ubuntu
apt
Fedora, RHEL
dnf
Arch
pacman · AUR
Alpine, NixOS
apk · Nix
macOS
Homebrew
Windows
WinGet · MSIX · Chocolatey · Scoop
Windows, deeper
autoruns · services · Authenticode
In practice

Gate the build. Keep the code.

Built to sit in a pipeline and say no, without sending your source anywhere.

CI gate

Fails closed

Exit 1 above your threshold, 2 on error, and 2 as well when a check could not run. SARIF lands in code scanning; postmortem ci writes the pipeline for GitLab, Azure DevOps and Jenkins.

# .github/workflows/postmortem.yml
- uses: mlab-sh/[email protected]
  with:
    online: true
    vulns: true
Privacy

Nothing leaves by default

No telemetry, no daemon, no account.

  • scan · tree · system
    fully offline
  • --online · --vulns
    package names and versions only, never your code
  • proxy · CA · mirrors
    built for locked-down networks
With mlab.sh

From finding to intel

Standalone by design. Connected to mlab.sh, it goes further.

  • --vulns
    CVE, GHSA and OSV matching via vuln.mlab.sh
  • --enrich
    every IOC in a report links to its mlab.sh analysis
  • Claude Code
    supply-chain audit and dependency vetting skills
All mlab.sh integrations →
Install

Ready in one minute.

Prebuilt for macOS, Linux and Windows on x86_64 and arm64. Then run postmortem scan . at the root of a repository.

brew tap mlab-sh/postmortem https://github.com/mlab-sh/postmortem.git
brew install postmortem
apt signing key 7178 94BC C0E0 57E4 F9BB F3CA C0E2 87DD 9609 A065 · binaries on GitHub releases · reference on doc.mlab.sh
Get started

Scan your project in one command

Open source under Apache-2.0, built and maintained by the mlab.sh team. Install it, run it at the root of a repository, and see what your dependencies do before your build runs them.

  1. 01
    postmortem scan .Malicious code in what you install, offline.
  2. 02
    postmortem tree . --onlineWho publishes your dependencies, and what changed.
  3. 03
    postmortem audit .One verdict for malware, risk and CVEs.