Signed Packages and Trust Policies
|
This section documents MSBuild 18.9, the .NET SDK 10.0.402 (with its This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The C# Reference bibliography lists the reference material consulted while preparing these pages. |
A NuGet package can carry two signatures. An author signature, added by the publisher, proves who built it; a repository signature, added by nuget.org to every package it accepts, proves where it came from. A consumer can simply let NuGet check that signed packages are intact, or go further and require that every package is signed by a signer it trusts. This page does both with NuGet 7.9.0 (.NET SDK 10.0.402) on Linux. Signing your own packages is on Signing Packages.
Inspecting signatures
dotnet nuget verify --all ~/.nuget/packages/humanizer.core/2.14.1/humanizer.core.2.14.1.nupkg
Verifying Humanizer.Core.2.14.1
Content hash: lQKvtaTDOXnoVJ20ibTuSIOf2i0uO0MPbDhd1jm238I+U/2ZnRENj0cktKZhtchBMtCUSRQ5v4xBCUbKNmyVMw==
Signature type: Author
Subject Name: CN=Humanizer (.NET Foundation), O=Humanizer (.NET Foundation), L=Redmond, S=wa, C=US, SERIALNUMBER=603 389 068
SHA256 hash: B0F7E4AA75AD5585ADD09821B41AFE260404DC59D373477E065AED0D9F21681C
Valid from: 03/11/2021 00:00:00 to 06/07/2024 23:59:59
Signature type: Repository
Subject Name: CN=NuGet.org Repository by Microsoft, O=NuGet.org Repository by Microsoft, L=Redmond, S=Washington, C=US
SHA256 hash: 5A2901D6ADA3D18260B9C6DFE2133C95D74B9EEF6AE0E5DC334C8454D1477DF4
Valid from: 02/16/2021 00:00:00 to 05/15/2024 23:59:59
Both certificates have expired, and the package still verifies (exit code 0): the signatures carry timestamps, and a signature made while its certificate was valid stays valid. An unsigned package — Ledgerline's own, from the local feed — fails verification with exit code 1:
error: NU3004: The package is not signed.
Package signature validation failed.
Source: dotnet nuget verify.
What restore checks
With the default signatureValidationMode of accept, restore checks that signed packages have not been modified
since signing (NU3008 if they have) and accepts unsigned packages. On Linux this verification is on by default since
the .NET 8 SDK; DOTNET_NUGET_SIGNATURE_VERIFICATION=false turns it off — a detailed restore log then contained no
signature lines at all. On macOS it is off by default and the documentation recommends leaving it off; on Windows it is
always on.
Source: Signed package verification: Windows, Linux, macOS.
Trusted signers
trustedSigners in nuget.config lists whose signatures are trusted. dotnet nuget trust maintains it:
| Command | Adds or does |
|---|---|
|
Show the trusted signers. |
|
Trust the author certificate that signed a local package. |
|
Trust the repository certificate on a local package ( |
|
Trust a source’s repository certificates, read from its service index. |
|
Trust a certificate by fingerprint. |
|
Refresh a repository’s certificates from its service index. |
|
Remove a signer. |
dotnet nuget trust author Humanizer ~/.nuget/packages/humanizer.core/2.14.1/humanizer.core.2.14.1.nupkg --configfile nuget.config
dotnet nuget trust source nuget.org --configfile nuget.config
dotnet nuget trust list --configfile nuget.config
Successfully added a trusted author 'Humanizer'.
Successfully added a trusted repository 'nuget.org'.
Registered trusted signers:
1. Humanizer [author]
Certificate fingerprint(s):
SHA256 - B0F7E4AA75AD5585ADD09821B41AFE260404DC59D373477E065AED0D9F21681C
2. nuget.org [repository]
Service Index: https://api.nuget.org/v3/index.json
Certificate fingerprint(s):
SHA256 - 0e5f38f57dc1bcc806d8494f4f90fbcedd988b46760709cbeec6f4219aa6157d
SHA256 - 5a2901d6ada3d18260b9c6dfe2133c95d74b9eef6ae0e5dc334c8454d1477df4
SHA256 - 1f4b311d9acc115c8dc8018b5a49e00fce6da8e2855f9f014ca6f34570bc482d
trust repository nuget.org without a package failed ("Required argument missing for command: 'repository'"): it
reads the certificate from a package; trust source is the form that reads it from the feed. Trusting the
nuget.org repository with --owners (--owners "dotnetfoundation;microsoft") narrows it to packages from those
nuget.org accounts.
Requiring trusted signatures
<config>
<add key="signatureValidationMode" value="require" />
</config>
With both signers above trusted, a project referencing Humanizer.Core, Newtonsoft.Json and the unsigned
Ledgerline restored the two nuget.org packages (both repository-signed by nuget.org) and rejected the third:
~/sign/S.csproj : error NU3004: Package 'Ledgerline 1.0.0' from source '~/lb/artifacts/feed': signatureValidationMode is set to require, so packages are allowed only if signed by trusted signers; however, this package is unsigned.
After dotnet nuget trust remove nuget.org, only the Humanizer author was trusted, and Newtonsoft.Json — author-
signed by Json.NET and repository-signed by nuget.org, neither trusted — was rejected:
~/sign/S.csproj : error NU3034: Package 'Newtonsoft.Json 13.0.3' from source 'https://api.nuget.org/v3/index.json': This package is signed but not by a trusted signer.
The same NU3034 appeared after switching back to accept: once a trustedSigners list exists, signed packages
must match it even in accept mode; accept only lets unsigned packages through. require is practical for
organisations that sign their internal packages and trust nuget.org’s repository certificate (with --owners), and it
blocks a tampered or substituted package even when no lock file would catch it.
Fingerprints and algorithms
trustedSigners entries store certificate fingerprints with their algorithm; dotnet nuget trust writes SHA-256
ones. On the signing side, NuGet 6.12 deprecated SHA-1 fingerprints for dotnet nuget sign/nuget sign
(--certificate-fingerprint): NU3043 is a warning in .NET 9 and an error in the .NET 10 SDK
(Signing Packages). When nuget.org
rotates its repository certificate, dotnet nuget trust sync nuget.org adds the new fingerprint (the three above
include past and current certificates).
Source: NU3043, NuGet 6.12 release notes.
Common mistakes
-
Expecting
acceptto ignore trusted signers — signed packages must still match the list. -
Trusting the nuget.org repository without
--ownersunderrequire— that trusts every package on nuget.org. -
Forgetting
trust syncafter a repository certificate rotation —requirestarts rejecting new packages. -
Enabling verification on macOS — documented as unsupported.