What policy enforcement means

TrustConfig.json is not just a personal trust list — it is the organizational record of which packages and publishers are approved for use. When it is checked into source control and the audit runs in CI, any package not on the approved list causes the build to fail. That is policy enforcement.

This means you can use TrustConfig.json to express organizational decisions beyond security:

The enforcement is automatic — developers do not need to remember to check. The CI gate and VS pre-build target enforce it on every build and every PR.

The three enforcement levels

Policy is enforced at three points, each catching a different class of violation:

LevelMechanismWhat it catches
Developer machine Directory.Build.targets pre-build target Unapproved packages before the first local build after a restore
CI/CD nuget-audit audit --check as a required status check Any PR or merge that introduces an unapproved package
Lock files packages.lock.json + RestoreLockedMode=true Unauthorized changes to the resolved graph — restore fails if the lock is out of date

All three levels together mean a package cannot enter the project silently. A developer adding an unapproved package must edit the project file (caught by the lock file on restore), restore (generating a new lock file that differs from the committed one), and build (where the pre-build target fires). The CI gate catches anything that slips through.

Run nuget-audit init --path <dir> to create Directory.Build.targets and a default TrustConfig.json. See the zero-trust workflow guide for full setup instructions.

Forcing package migrations

Removing a package or owner from TrustConfig.json causes CI to fail on any project that still uses it. This is a controlled mechanism for forcing teams to migrate away from deprecated or unwanted packages.

Example: migrating off a deprecated package

// Before: Newtonsoft.Json is in trustedPackages
{
  "trustedOwners": ["Microsoft", "dotnetfoundation"],
  "trustedPackages": [
    { "id": "Newtonsoft.Json", "version": "13.0.3" }
  ]
}

// After: remove the entry to block further use
{
  "trustedOwners": ["Microsoft", "dotnetfoundation"],
  "trustedPackages": []
}

Any project that still references Newtonsoft.Json will now fail CI with an Untrusted status. The failure tells the developer exactly which package needs attention — migrate off it, or re-approve it if the decision is reversed.

Communicate before removing

Removing an entry blocks builds immediately. Give teams notice before committing the change to TrustConfig.json, and document the planned removal in your project's decision log.

Example: moving an owner from broadly trusted to per-version review

Removing an owner from trustedOwners does not immediately block existing pinned versions in trustedPackages. Any package from that owner that is not explicitly pinned will be flagged as VerifiedUnknownOwner and require review.

This is useful when you want to increase scrutiny of a publisher's packages without immediately blocking builds — moving from "broadly trusted" to "reviewed per version."

Compliance and architectural controls

The same mechanism supports organizational rules beyond security:

Prefer internal or forked packages

If your organization maintains internal forks or mirrors of public packages, keep the public package out of TrustConfig.json. Any project that accidentally references the public version will fail CI, directing developers to the internal package instead.

Enforce System.* over third-party equivalents

For functionality now covered by the .NET runtime — System.Text.Json replacing Newtonsoft.Json, Microsoft.Extensions.* replacing earlier third-party equivalents — remove the third-party package from the trust list. Add a comment to TrustConfig.json documenting the architectural decision so the reason is visible when someone hits the CI failure.

Compliance-driven exclusions

If legal or compliance requirements prohibit specific packages or licenses, omitting them from TrustConfig.json creates an automatic enforcement gate. When a developer adds such a package — intentionally or as a transitive dependency — the CI failure names the package and owner, providing an audit trail.

Brownfield adoption

Introducing policy enforcement into an existing project requires a one-time approval pass to baseline the current state before enforcement begins.

# 1. See everything currently in the graph and its trust status
nuget-audit audit --all --path .

# 2. Generate copy-paste entries for TrustConfig.json
nuget-audit audit --package-list --include-existing --path .

# 3. Edit TrustConfig.json: add owners to trustedOwners,
#    add specific versions to trustedPackages

# 4. Re-run until clean
nuget-audit audit --path .

# 5. Lock the graph and commit
dotnet restore --force-evaluate
git add packages.lock.json TrustConfig.json
git commit -m "Baseline NuGet trust policy"

After the baseline commit, CI enforcement begins. Any new package added to the project must be approved in TrustConfig.json before CI passes.

--include-existing for a full inventory

--package-list --include-existing shows all packages grouped by trust status — useful for the initial review pass on a large project with many existing dependencies.

When policy breaks down

The most common ways the enforcement model fails, and what to do about them:

Failure modeHow it happensPrevention
Lock file not committed Developer runs --force-evaluate without committing the updated lock file CI restore fails if the committed lock file does not match; the advisory check flags missing lock files
CI check not required Audit runs in CI but is not a required status check — PRs can merge even if it fails Make nuget-audit audit --check a required status check in branch protection rules
Pre-build target missing Directory.Build.targets not created or not at solution root --check warns on this condition; run nuget-audit init to create it
TrustConfig.json grows without review Developers add entries to unblock CI without reviewing the package Require a designated reviewer on TrustConfig.json changes via CODEOWNERS
Multiple solutions, config in wrong location TrustConfig.json not found at expected path Use --trust-config to specify the path explicitly in the CI command and Directory.Build.targets
CODEOWNERS for TrustConfig.json

Add a CODEOWNERS entry requiring a designated reviewer for any PR that modifies TrustConfig.json. This prevents the trust list from drifting without oversight.

# .github/CODEOWNERS
TrustConfig.json    @your-org/security-reviewers
Setting up the policy for the first time?

See the zero-trust workflow guide for the complete setup sequence — lock files, CI gates, VS pre-build enforcement, and the ongoing package update workflow.