Skip to content

Back to the catalog

PackageGuard
github.comrepo

PackageGuard

PackageGuard is an open-source .NET CLI tool that scans NuGet, npm, pnpm and Yarn dependencies (direct and transitive) across a codebase, enforcing hierarchically-configured allow- and deny-lists for licenses, packages and versions. It scores each package's Legal, Security and Operational risk using signals like OSV vulnerability data, maintainer activity, package signing and release cadence, and can emit a CycloneDX or SPDX SBOM enriched with OSV vulnerability data, plus console, HTML and SARIF output for CI/GitHub code scanning. It's positioned as a free alternative to commercial supply-chain tools like Black Duck and Snyk.

TL;DR Open-source .NET CLI that scans NuGet/npm/pnpm/Yarn dependencies, enforces license/package allow-deny lists, scores supply-chain risk, and emits SBOMs (CycloneDX/SPDX) with SARIF for CI.
Document

What it is

PackageGuard is a .NET CLI supply-chain scanner (author: Dennis Doomen). The summary covers scope and outputs; what it can't carry is the operational surface — the flags, config-discovery behavior, and deployment/runtime requirements an engineer needs before adopting it into CI.

How it works

Features are gated behind explicit flags rather than always-on:

  • --report-risk turns on Legal/Security/Operational scoring (license compatibility, OSV vulnerabilities, maintainer activity, package signing, release cadence, "and dozens more").
  • --sbom emits a CycloneDX or SPDX JSON SBOM with purls and declared-vs-concluded license evidence. OSV vulnerability enrichment of the SBOM only happens when --sbom is combined with --report-risk.
  • --use-caching caches package/license/risk data including GitHub responses and per-repo risk profiles; freshness is tuned with --risk-cache-max-age-hours and --refresh-risk-cache.

Allow/deny-lists (licenses, packages, versions) are discovered hierarchically across solution-, project- and repository-level config files, so configuration can be layered rather than centralized. Licenses resolve through a fallback chain of fetchers — NuGet/npm metadata → GitHub repo → downloaded license text — degrading gracefully when a source has no answer. The HTML report backs each score with a collapsible, collapsed-by-default Evidence panel naming exact packages, versions, and GHSA/OSV ids.

Preconditions / Affected

  • Runs as a .NET global tool or a portable cross-platform (Windows/Linux/macOS) deployment — no CI-specific plugin.
  • To scan npm/pnpm/Yarn projects, NPM, PNPM and Yarn must be available in PATH. This is stated as a build requirement but is the practical gating condition for multi-ecosystem scanning; a .NET-only build agent won't cover the JS ecosystems.
  • Building from source needs the .NET 9.0 SDK or later; the repo multi-targets net9.0 and net10.0, with global.json pinning local builds to the .NET 10 SDK.

What to do

Combine the flags for full output in one CI run:

--report-risk --sbom --use-caching

Emit SARIF to surface violations and risk findings in GitHub code scanning. If GitHub throttling is a concern in CI, rely on --use-caching (which caches GitHub responses) and tune --risk-cache-max-age-hours.

Caveats

The author frames this as filling the gap between Dependabot and commercial tools (Snyk, Black Duck) for smaller teams "that may not need" full commercial functionality — an explicit positioning, not a feature-parity claim. Risk scoring and SBOM enrichment are opt-in; a default invocation without --report-risk/--sbom produces neither.

Technologies named here

Techniques named here

  • Allow-/deny-list policy enforcement
  • License resolution chain
  • Package risk scoring
  • Risk-based policy gating
  • Evidence-backed risk reporting
  • SBOM generation
  • SBOM vulnerability enrichment
  • Dependency graph traversal
  • Package explain/audit trail
  • Caching of package/license/risk data