hashwatch CLI — verify files#

Verify files against HashWatch’s known-good corpus from a terminal or a build pipeline, using the open-source hashwatch CLI (Apache-2.0, standard-library Go) — a small, standalone binary with no dependency on the HashWatch platform.

hashwatch verify <file>...        # hash local file(s) and verify
hashwatch verify --url <url>      # stream-download, hash, and verify
hashwatch verify --sha256 <hex>   # verify a precomputed digest
cat file | hashwatch verify -     # hash stdin

Flags: --api-key (or $HASHWATCH_API_KEY) is optional — it widens the check to the full known-good corpus; --offline checks against the local cache only; --refresh updates it now · --json · --quiet · --allow-unknown.

Exit codes make it easy to fail a build on an unverified artifact — run the binary as a build step and check its result:

CodeMeaning
0every input is known-good
1at least one input is unknown
2usage or runtime error

Without a key vs. with an API key#

The CLI is free and needs no account — a key changes what it checks against, not whether it works:

No key (free)With an API key
Checks againstToday’s public verified set — the current release of each tracked product (the same data as the dashboard)The full known-good corpus — NIST NSRL/BinTrust (~72 M hashes) plus every release HashWatch has ever recorded
HowA local snapshot downloaded from the public feed at most once a day, then reusedA live, authenticated lookup per run
Works offline✓ — after the first run; force with --offline, update with --refresh✗ — needs the API
Older versions / past releases✗ — anything that isn’t today’s release comes back unknown
OS-shipped binaries (certutil.exe, bash, …)✓ — covered by the NSRL corpus
hashwatch verify ./installer.exe                     # free: today's verified set, cached locally
hashwatch verify --offline ./installer.exe           # free: cache only, no network at all

export HASHWATCH_API_KEY=...                         # any paid tier's key works
hashwatch verify ./installer.exe                     # full corpus, incl. older releases + NSRL

Reading a free-mode unknown honestly: it means “not in today’s verified set” — the file may still be a perfectly legitimate older release. If an unknown matters (CI gate, IR triage), add a key so the full corpus can answer definitively. Keys are issued with any paid account — see Tiers.

Install#

The CLI is Apache-2.0 and standard-library-only (no dependency on the HashWatch platform; no account needed for the free path). Everything is served from cli.hashwatch.us — no public repo, no auth. Pick one:

  • Prebuilt binary (no Go needed):
    curl -fsSL https://cli.hashwatch.us/install.sh | sh
    Downloads the binary for your OS/arch and verifies its SHA-256. Windows: grab the .exe from https://cli.hashwatch.us/hashwatch.
  • go install (Go 1.26+):
    go install cli.hashwatch.us/hashwatch@latest
    The module path is a vanity import path served from cli.hashwatch.us/hashwatch; the binary is named hashwatch.
  • Build from source (from a checkout of the HashWatch repo):
    cd cli && go build -o hashwatch .      # then put ./hashwatch on your PATH
  • Container:
    docker build -f Dockerfile.cli -t hashwatch-cli .

Use in CI/CD pipelines#

hashwatch verify is exit-code driven, so it drops into any pipeline as a supply-chain gate: hash the artifact you built or downloaded and fail the job (exit 1) if it isn’t known-good. Install it per the Install section above.

GitHub Actions#

# .github/workflows/verify.yml
name: verify-artifact
on: [push]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with: { go-version: '1.26' }
      - run: go install cli.hashwatch.us/hashwatch@latest
      - name: Verify the installer is a known-good release
        env:
          HASHWATCH_API_KEY: ${{ secrets.HASHWATCH_API_KEY }}   # optional: widens to the full corpus
        run: hashwatch verify ./dist/installer.exe

The job fails if the file isn’t known-good. Omit the env: block to run free against today’s public verified set; add --allow-unknown to report without failing the build.

GitLab CI#

verify-artifact:
  image: golang:1.26
  variables:
    HASHWATCH_API_KEY: $HASHWATCH_API_KEY   # optional: full corpus (set as a masked CI/CD variable)
  script:
    - go install cli.hashwatch.us/hashwatch@latest
    - hashwatch verify ./dist/installer.exe

Pre-download supply-chain gate (any shell)#

Verify a third-party installer before you execute it — hash it straight from its URL, no local copy needed:

hashwatch verify --url https://example.com/tool-setup.exe \
  || { echo "refusing to run an unverified installer"; exit 1; }

Or gate on an already-published digest without downloading anything:

hashwatch verify --sha256 "$EXPECTED_SHA256"

Container image (no Go toolchain in the runner)#

docker build -f Dockerfile.cli -t hashwatch-cli .
docker run --rm -v "$PWD:/w" -w /w -e HASHWATCH_API_KEY \
  hashwatch-cli verify ./dist/installer.exe

JSON for downstream steps: add --json to emit { "results": [...], "unknown": N } for a later step to parse; the exit code is unchanged, so the gate still works.