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:

EcosystemArtifact verified
npmthe published package tarball
PyPIthe published source distribution / wheel
Go modulesthe published module archive
Homebrewthe formula bottle / cask artifact (first-party formulae.brew.sh SHA-256)
Docker / OCIthe container image manifest digest - the content-addressed identity of a popular official base image (no layers are pulled)
VS Code extensionsthe 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#

teams

A 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 & pathPurpose
GET /api/v1/intel/packages/changesThe change-alert feed (newest first). ?watched=true scopes it to your watchlist; ?ecosystem=npm|pypi|go filters by ecosystem.
GET /api/v1/intel/packages/watchYour account’s watchlist.
POST /api/v1/intel/packages/watchWatch 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#

teams

Point 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 classified known_vendor_release, known_file, or unknown,
  • 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.json

Typosquat & dependency-confusion#

teams

Check 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 the nearest_known legitimate name and the distance),
  • dependency_confusion - a name you listed in internal_names that also exists publicly, the setup for a dependency-confusion substitution, or
  • clear - 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"]}'