nuget-audit audit

Run a NuGet package security audit.

nuget-audit audit --path <path> [options]
OptionDefaultDescription
--path.Path to .csproj, .sln, .slnx, or directory. Auto-discovers .slnx.sln.csproj when given a directory.
--allShow all packages regardless of trust status, including Verified, TrustedPackage, and PrivateFeed.
--verboseDisable per-owner transitive condensing and show all recently-published entries. Independent of --all; combine as needed.
--package-listOutput packages as formatted copy-paste entries for TrustConfig.json, grouped by trust category.
--include-existingWith --package-list: replace the "needs review" list with a full inventory of all packages grouped by trust status. Use for a complete dependency footprint view.
--checkCounts only — packages needing review, deprecated, vulnerable. Also reports setup advisory conditions (missing lock file, RestoreLockedMode, pre-build target, or Package Source Mapping). Exits with code 1 if any counts are non-zero or any advisories are present. Use in CI/CD pipelines and VS pre-build targets.
--formattableOutput format: table, csv, or json.
--outputWrite output to a file. Requires --format csv or --format json. For plain-text table output, use shell redirection instead.
--trust-configCWDExplicit path to TrustConfig.json or its containing directory.

--check output

Packages needing trust review: 2
Deprecated packages:           0
Packages with vulnerabilities: 1

Security advisory: No packages.lock.json found — lock file enforcement is missing.

Run nuget-audit audit for full details.

Exits with code 0 when all counts are zero and no advisory conditions are present. Exits with code 1 if any count is non-zero or if any of the following advisory conditions are detected: missing packages.lock.json, RestoreLockedMode not set, no Directory.Build.targets with a nuget-audit invocation, or Package Source Mapping not configured.

nuget-audit preview-update

Preview transitive graph changes before adding or updating a package. By default, runs an exact dotnet restore into a temp directory so the resolved graph matches what would actually be installed — nothing lands in your real NuGet cache.

nuget-audit preview-update <package-id> [--version <ver>] --path <path>
OptionDefaultDescription
<package-id>requiredPackage ID to add or update.
--versionlatestTarget version. Omit to resolve to the latest available on nuget.org. Required for private-feed packages.
--path.Path to solution, project, or directory.
--trust-configCWDPath to TrustConfig.json.
--fastoffUse approximate BFS resolver instead of dotnet restore. Faster, but results may not match what actually gets installed. Not recommended for security-critical decisions.

Output shows ADDED, CHANGED, and REMOVED sections relative to the current graph. Each new or changed package is evaluated against the same trust model as the main audit, including the recently published check.

Private-feed packages

Private-feed packages fall back to the approximate BFS resolver (exact restore is not supported for private feeds). A warning is shown in the output. --version is required for private-feed packages — the latest version cannot be auto-resolved without querying nuget.org.

Supply chain transition warning

If the currently installed version of a package came exclusively from a private feed and the target version now appears on nuget.org, preview-update emits a warning before the normal output. A red alert (⛔) fires when the publisher has no nuget.org prefix reservation or is not a trusted owner — a potential dependency confusion attack. A yellow notice (⚠) fires when the publisher is verified and trusted — a likely legitimate vendor move worth confirming before applying.

Package Source Mapping conflict

If your NuGet.config has Package Source Mapping and the target version is available on nuget.org but PSM restricts that package to a private feed, preview-update emits a specific error explaining which feed is blocking the search and how to add a nuget.org mapping to resolve it — rather than a generic restore failure.

Stale lock file fallback

When RestoreLockedMode=true is in effect and the lock file is out of date, dotnet list package will fail. preview-update detects this and falls back to reading packages.lock.json directly so you can preview the change before running dotnet restore --force-evaluate.

nuget-audit preview-restore

Resolve the full transitive package graph by running dotnet restore into a temp packages directory. Use before the first restore on a newly cloned project, or any time you have edited package references and want to see the full graph before running the real restore. Package files land in the temp directory (deleted after the preview); the real obj/ directory is never touched.

nuget-audit preview-restore --path <path>
OptionDefaultDescription
--path.Path to solution, project, or directory.
--trust-configCWDPath to TrustConfig.json.
--fastoffUse approximate BFS resolver instead of dotnet restore. Requires --framework for TFM selection. Not recommended for security-critical decisions.
--frameworkauto-detectedTFM for dependency resolution — only used with --fast.

Output is a single ADDED list of every package that would land on disk. Private-feed packages appear as PrivateFeed with a warning — their transitive dependencies cannot be resolved via nuget.org.

Clone with the git CLI only.

Visual Studio and some other tools restore automatically on clone or solution open, bypassing the pre-restore review window — the narrow gap between cloning and the first restore during which you can inspect the full package graph before anything is downloaded. The same window applies any time you edit package references before running dotnet restore.

Preview mode decision table

SituationCommand
Before the first restore (newly cloned)preview-restore
After editing package referencespreview-restore
Adding a new packagepreview-update <id>
Updating an existing packagepreview-update <id> --version <ver>
Reviewing what is currently restoredaudit
Preview accuracy

By default both preview commands run an exact dotnet restore so the resolved graph matches what would actually be installed. Use --fast to switch to the approximate BFS resolver (faster, but may not match dotnet restore). Always follow any preview with a full nuget-audit audit after restoring.

nuget-audit init

Create TrustConfig.json and Directory.Build.targets to set up a project for the zero-trust workflow.

nuget-audit init [--path <dir>] [--force]
OptionDefaultDescription
--path.Directory in which to create the files. Accepts a directory, .sln/.slnx file, or explicit .json path — the containing directory is used in all cases.
--forceOverwrite existing files. Without --force, existing files are skipped silently.

TrustConfig.json is created with the default trusted owners (Microsoft, dotnetfoundation, aspnet) and a placeholder entry in trustedPackages. Directory.Build.targets adds a pre-build MSBuild target that runs nuget-audit audit --check automatically before each Visual Studio build whenever the lock file has changed. Add .nuget-audit-ok to .gitignore — it is a machine-local sentinel file created by the target.

Running init again on a project that already has one file creates the missing file without touching the existing one.

nuget-audit trust-owner

Add a nuget.org account name to the trustedOwners list.

nuget-audit trust-owner <owner> [--path <dir>] [--trust-config <path>]

Use the exact account name shown on the package's nuget.org page under "Owners" — not the display name. If the owner is already in the list, exits with no change.

nuget-audit trust-package

Add or update a package/version entry in the trustedPackages list.

nuget-audit trust-package <id> <version> [--path <dir>] [--trust-config <path>]

If the package ID already exists with a different version (VersionChanged scenario), the entry is updated in place. If the exact ID+version is already trusted, exits with no change.

nuget-audit guide

Show a concise workflow walkthrough in the terminal for new and ongoing use.

nuget-audit guide

nuget-audit explain

Show an in-depth explanation of a security concept, with context for the zero-trust workflow. Advisory messages reference the relevant topic directly — e.g. a missing lock file advisory says Run nuget-audit explain lock-files for setup steps.

nuget-audit explain <topic>
TopicDescription
lock-filesLock file setup and enforcement — RestorePackagesWithLockFile to generate lock files, RestoreLockedMode to enforce them; why deterministic restores are foundational to the zero-trust workflow
psmPackage Source Mapping and dependency confusion — how PSM prevents NuGet from resolving packages from unintended feeds
exec-contentExecutable content in NuGet packages — why MSBuild targets and Roslyn analyzers expand the trust surface beyond the package library itself

Omit the topic to list all available topics: nuget-audit explain

Output fields

The default table format shows these fields. csv and json output includes additional fields — see below.

FieldDescription
TypeDirect or Trans (transitive). JSON field name: dependencyType.
PackageIdPackage name. JSON field name: packageId.
VersionResolved version.
Ownersnuget.org account name(s). In table output, truncated as FirstOwner +N when there are multiple owners. CSV returns all owners as a comma-separated string; JSON returns them as an array. See also Authors below — these are different fields.
VerifiedYes = nuget.org prefix reserved; No = unverified; N/A = private feed. JSON: boolean or null.
TrustTrust status — see trust model. Table output uses abbreviated display labels: Approved (TrustedPackage), !VerChg! (VersionChanged). VerifiedUnknownOwner displays as Untrusted — the Verified column distinguishes it from a fully unverified package.. CSV and JSON return the full status name. JSON field name: trustStatus.
DeprDeprecated on nuget.org. JSON field name: isDeprecated.
VulnHas known vulnerabilities. Use dotnet list package --vulnerable for severity levels and advisory URLs. JSON field name: hasVulnerabilities.
ExecExecutable content found in local NuGet cache: MSBld (MSBuild .props/.targets), Alyzr (Roslyn analyzer), Tools (executables in tools/). - = in cache, confirmed clean. ? = not in cache, could not be inspected. Column omitted in preview mode and when no displayed package has exec data. JSON field name: executableContent (string array, or null in preview mode meaning not yet inspected; empty array means inspected and clean). CSV field name: ExecutableContent (pipe-separated string, - = clean, ? = not inspected). Run nuget-audit explain exec-content for context on why this matters.

CSV and JSON additional fields

CSV and JSON output include additional package metadata not shown in table format:

FieldDescription
AuthorsAuthor names as declared in the package manifest. This is self-reported by the publisher and is distinct from Owners, which is the verified nuget.org account. An attacker can set Authors to any value — only Owners is authoritative for trust decisions.
LicenseExpressionSPDX license expression (e.g. MIT, Apache-2.0). Empty for older packages that predate the SPDX standard.
LicenseUrlLicense URL. Populated for older packages that use a URL instead of an SPDX expression.
PublishedPublication date in ISO 8601 format (UTC). Useful alongside the recentDaysThreshold flag to understand exactly when a package was released.
ProjectUrlPackage project or repository URL as declared by the publisher.

Example output

Filtering to show only packages needing review...
Found 2 package(s) needing review.

Type    PackageId                Version  Owners         Verified  Trust          Depr  Vuln  Exec
------  -----------------------  -------  -------------  --------  -------------  ----  ----  ----
Direct  FakeExcel.Core           3.1.0    fake-author1   No        Untrusted      No    No    MSBld, Alyzr
Trans   FakeSpreadsheet.Format   1.0.5    fake-author2   No        Untrusted      No    No    -

=== Packages needing review with executable content ===
  FakeExcel.Core 3.1.0  [Untrusted]  MSBld, Alyzr

For transitive packages needing review, trace the dependency chain:
  dotnet nuget why ".\MySolution.sln" FakeSpreadsheet.Format

Recently published (within 14 days — higher supply chain risk):
  FakeExcel.Core 3.1.0  published 2026-03-29 (4 days ago)  [Untrusted]

--package-list output

Run nuget-audit audit --package-list to generate formatted copy-paste entries for TrustConfig.json. Output is grouped into sections (only sections with matches are shown):

# --- Prefix-verified packages (unknown owner) ---
# These packages have nuget.org prefix reservation but their owner is not in
# trustedOwners. Pin by version below, or add the owner to trustedOwners (see end).

{ "id": "SomePackage", "version": "2.0.0" },

# --- Unverified packages ---
# These packages have no nuget.org prefix reservation. Review carefully before trusting.

{ "id": "FakeExcel.Core", "version": "3.1.0" },

# --- trustedOwners alternative (prefix-verified packages only) ---
# Instead of pinning by version, add these publishers to trustedOwners to trust
# all current and future versions.

"SomeOrg",

Add --include-existing to replace the "needs review" list with a full inventory of all packages sorted and color-coded by trust status — useful for auditing your complete dependency footprint or verifying that previously approved packages are still accounted for.

Building your trust lists

Initial setup on an existing project

  1. Run nuget-audit audit --path . to see what needs review.
  2. For each flagged package, check the Owners column and the package's nuget.org page ProjectUrl.
  3. Run nuget-audit audit --package-list to generate copy-paste entries for all flagged packages at once.
  4. Decide for each: add the owner to trustedOwners (trusted broadly, all versions) or add the specific ID+version to trustedPackages (reviewed manually, re-review on version change).
  5. Re-run the audit to confirm quiet output.

When a package version changes

The VersionChanged status flags a package in trustedPackages whose version has changed since you last reviewed it. This is intentional — a new version is new code. Review the changelog and update your entry:

nuget-audit trust-package SomePackage 3.0.0 --path .

This updates the existing entry in place.

Package policy enforcement

Beyond security, nuget-audit enforces organizational package policies. The audit + CI gate pattern works for any rule expressible as a trust status.

Enforcing a package migration

Example: your organization is migrating away from a third-party logging package to Microsoft.Extensions.Logging.

  1. Remove the package or its owner from TrustConfig.json — do not add it to trustedPackages for the new version.
  2. The CI gate (nuget-audit audit --check) now fails on any project still referencing it.
  3. Developers see which projects need migration. Use dotnet nuget why to trace transitive references.
  4. Projects must migrate before the CI gate passes, enforcing the policy without manual policing.

Other policy enforcement examples

Compliance export

Export audit results for compliance records or external tooling:

# CSV export
nuget-audit audit --format csv --output "audit-2026-01-05.csv" --path .

# JSON export
nuget-audit audit --format json --output "audit-2026-01-05.json" --path .

CSV and JSON output include all packages regardless of trust status, with all fields including the full owners list. Use with --all to ensure no packages are filtered before export.

TrustConfig.json reference

{
  "trustedOwners": [
    "Microsoft",
    "dotnetfoundation",
    "aspnet"
  ],
  "trustedPackages": [
    { "id": "SomePackage", "version": "2.0.0" }
  ],
  "recentDaysThreshold": 14
}
FieldDescription
trustedOwners nuget.org account names whose prefix-verified packages are trusted at any version. Use the exact account name from the package's nuget.org "Owners" field — not the display name. Add your organization's nuget.org accounts here.
trustedPackages Packages manually reviewed and pinned to a specific version. A version change triggers VersionChanged status. Required for unverified publishers; optional for verified publishers where you want per-version review.
recentDaysThreshold Versions published within this many days are flagged as higher supply chain risk regardless of trust status. Default: 14. Adjust to your organization's risk tolerance — 14 days covers most attacks; 30 days covers nearly all. In audit output, a Recently published section lists any packages within the window; changing this value widens or narrows that section.

Known limitations

This tool audits package metadata. It cannot inspect package code or runtime behavior.

ThreatCovered?Notes
Unknown package from unknown publisher✅ Yes
Package impersonating a trusted author name✅ Yesverified + trusted owners catches this
Unverified package at an unexpected version✅ YestrustedPackages exact ID+version match
Known CVE in any package✅ YesVuln column; use dotnet list package --vulnerable for severity and advisory URLs
Packages introduced before any audit⚠️ PartialUse preview-restore before the first restore; VS and some templates restore automatically
Changed transitive pulled in by restore⚠️ Partialpreview-update before --force-evaluate; lock files prevent silent changes
Compromised account publishing a new version⚠️ PartialRecently published section flags versions within threshold
Ownership transfer followed by malicious release⚠️ PartialCovered by recency check when the malicious version is published within the threshold window. The unmitigated residual is a version that has aged past the threshold and has not yet been flagged as malicious by the community — the two conditions an attacker must simultaneously achieve. Pair with NuGet package signing (<trustedSigners>) for ownership-transfer detection independent of the recency window — effective only if the original publisher was using author signatures, which many do not.
Exec content in packages⚠️ Post-restore onlyExec column flags presence; not available in preview mode — run the full audit immediately after restore, before the next build
Initial version already malicious❌ NoOut of scope for any automated tool — mitigate by checking download counts, project activity, and community reputation before adding any new dependency

What dotnet restore can execute

dotnet restore does not run arbitrary package code, but can run MSBuild targets hooked into the Restore target by packages already in the evaluated graph. A newly downloaded package cannot affect the same restore that fetched it — but its targets can run on the next restore or build.

This is why the recommended workflow is: preview → restore → audit immediately, before the next build. Build is the more common execution trigger in practice.

Pair nuget-audit with: