PkgGuard - Package & Supply-Chain Integrity#
PkgGuard extends HashWatch’s verified-hash model from vendor applications to the
software packages your builds depend on. A verified hash for left-pad@1.3.0 is
the same trustworthy reference as a verified hash for putty.exe - just for a
registry artifact instead of a desktop installer.
**Why it matters.** A published package version is **immutable** - the artifact for a given `package@version` should never change. If the hash you see today differs from what was published, that is a strong **republish / account-compromise** signal: the exact class of attack behind the high-profile npm and PyPI takeovers.
What’s covered#
PkgGuard tracks verified published-artifact hashes across the major open-source package registries:
| Ecosystem | Artifact verified |
|---|---|
| npm | the published package tarball |
| PyPI | the published source distribution / wheel |
| Go modules | the published module archive |
| Homebrew | the formula bottle / cask artifact (first-party formulae.brew.sh SHA-256) |
| Docker / OCI | the container image manifest digest - the content-addressed identity of a popular official base image (no layers are pulled) |
| VS Code extensions | the published .vsix package (the SHA-256 the Marketplace gallery exposes) |
| Debian / Ubuntu (apt) | the binary .deb for a curated set of core packages (first-party SHA-256 from the distro’s Packages index; Ubuntu tracks the security-patched version) |
Versions are always discovered dynamically - HashWatch records the registry’s current published version, never a hardcoded one. Coverage is a curated set of widely-used, supply-chain-critical packages and grows over time.
Where to find it#
Package hashes appear on the public dashboard under the Packages tab. Each entry shows:
- the package and its current version,
- SHA-256 (plus SHA-1 / MD5 where applicable), each one-click copyable,
- the exact registry source the hash was taken from, and
- whether the hash was independently re-computed by downloading the artifact (✓ verified) or read from the registry’s published manifest.
This is part of the free public reference - no account required, same as the daily application hashes.
Using it in your pipeline#
Confirm a dependency before you trust it:
# What is the verified hash of the current published version?
curl 'https://api.hashwatch.us/public/hash-of-day?executable=left-pad%20(npm)'Compare the result against the artifact your build resolved. A match is assurance the artifact is the genuine published release; a mismatch warrants investigation.
Watched packages & change alerts#
teamsA private, account-scoped capability for teams
accounts: watch
the packages your builds depend on and read a feed of published-hash-change alerts.
Because a published package@version is immutable, any change to its recorded hash is a
high-signal supply-chain anomaly (republish / account compromise) - this turns the
immutability guarantee above into an active early-warning signal.
Requires the intel:packages permission. All routes are scoped to your own account.
| Method & path | Purpose |
|---|---|
GET /api/v1/intel/packages/changes | The change-alert feed (newest first). ?watched=true scopes it to your watchlist; ?ecosystem=npm|pypi|go filters by ecosystem. |
GET /api/v1/intel/packages/watch | Your account’s watchlist. |
POST /api/v1/intel/packages/watch | Watch a package - body {"ecosystem":"npm","package_name":"left-pad"}. |
DELETE /api/v1/intel/packages/watch/{id} | Stop watching a package. |
# Watch a dependency, then check for any published-hash changes in your set
curl -X POST 'https://api.hashwatch.us/api/v1/intel/packages/watch' \
-H "X-API-Key: <team>.<secret>" -H 'Content-Type: application/json' \
-d '{"ecosystem":"pypi","package_name":"requests"}'
curl 'https://api.hashwatch.us/api/v1/intel/packages/changes?watched=true' \
-H "X-API-Key: <team>.<secret>"Each alert reports the package, version, the previous and latest SHA-256, and when the change was observed. Alerts are poll-based today (query the feed on your schedule); webhook delivery is a future option. Historical package hashes are also available through the authenticated history API (/reference/tiers/).
SBOM scanning#
teamsPoint HashWatch at the software bill of materials your build already produces and get an
integrity + risk report for every component in one pass. Submit a CycloneDX or SPDX
JSON SBOM (up to 16 MB) to POST /api/v1/intel/sbom and, for each component, HashWatch:
- matches any embedded hash (SHA-256 / SHA-1 / MD5) against the known-good corpus - the
same engine as
/intel/lookup, so a component is classifiedknown_vendor_release,known_file, orunknown, - runs name-only typosquat analysis on the component name, and
- attaches any known CVE advisories for tracked packages.
The SBOM is parsed in memory and discarded - it is never stored. Requires the
intel:packages permission. The response carries a summary (component counts by
classification and risk) plus a per-component breakdown. The same tool is available in the
admin console under Supply Chain (/admin/supply-chain).
curl -X POST 'https://api.hashwatch.us/api/v1/intel/sbom' \
-H "X-API-Key: <team>.<secret>" -H 'Content-Type: application/json' \
--data-binary @sbom.cdx.jsonTyposquat & dependency-confusion#
teamsCheck a set of dependency names for look-alike and confusion attacks without fetching a
single package - the analysis is name-only. Submit names to POST /api/v1/intel/typosquat
(up to 200 per request) and each is flagged as:
known- an exact match to a popular / tracked package,typosquat- within edit distance of, or a look-alike of, a popular name (the result includes thenearest_knownlegitimate name and thedistance),dependency_confusion- a name you listed ininternal_namesthat also exists publicly, the setup for a dependency-confusion substitution, orclear- no match and no risk detected.
Requires the intel:packages permission. Also available in the console under Supply Chain
(/admin/supply-chain).
curl -X POST 'https://api.hashwatch.us/api/v1/intel/typosquat' \
-H "X-API-Key: <team>.<secret>" -H 'Content-Type: application/json' \
-d '{"packages":[{"ecosystem":"npm","name":"expresss"}],
"internal_names":["mycorp-utils"]}'