Skip to main content
    Guides & Tutorials

    How to Sign a NuGet Package (Step by Step)

    Sign a NuGet package with dotnet nuget sign: use a hardware-based code signing certificate, add an RFC 3161 timestamp, register it on NuGet.org, then verify.

    MS
    My-SSL Security Team
    ·
    12 min read
    ·Published July 18, 2026·Last updated July 18, 2026

    The short answer

    To sign a NuGet package, run dotnet nuget sign MyPackage.nupkg with a code signing certificate and an RFC 3161 timestamp URL. Since June 1, 2023 that certificate's private key must live on certified hardware — a USB token, an HSM, or a cloud signing service — so instead of pointing at a .pfx file you reference the certificate in your store by its SHA-256 fingerprint. To ship on NuGet.org the primary signature must be an author signature, it must carry one valid timestamp, and you must register the certificate's fingerprint on your NuGet.org account first.

    What you need before you sign

    Signing a NuGet package takes three things: the package itself as a .nupkg, a publicly trusted code signing certificate whose key is held on hardware, and a command-line signer — either the classic nuget sign (NuGet CLI, Windows) or dotnet nuget sign, built into the .NET SDK since version 6. If you plan to publish to NuGet.org, add a fourth: the certificate has to be registered on your account before the feed will accept an author-signed upload.

    It helps to know what signing does and doesn't buy you. An author signature proves the package came from you and hasn't been tampered with since — a claim that stays attached to the file across mirrors, proxies, and offline copies. It does not encrypt the package or hide its contents, and it isn't the same as the repository signature NuGet.org stamps on everything it serves. We map both layers out below.

    The five stages of signing and publishing a NuGet packageA left-to-right pipeline: build the .nupkg, author-sign it with a code signing certificate, add an RFC 3161 timestamp, then push to NuGet.org, which verifies the author signature and adds its own repository counter-signature. The timestamp stage is highlighted because NuGet.org requires it.Pack.nupkgAuthor-signyour certTimestampRFC 3161Pushnuget pushNuGet.orgverifies + repo-signsSkip the timestamp and NuGet.org rejects the upload — and the signature dies with the certificate.
    Signing is one step in a chain: the timestamp (the gold box) is the one publishers forget, and it's the one NuGet.org refuses to accept a package without.

    The certificate — and where the key lives

    You need a code signing certificate: one whose Extended Key Usage lists id-kp-codeSigning, with an RSA key of at least 2048 bits. For NuGet.org it must chain to a root that ships trusted on Windows — self-signed and self-issued certificates are rejected. This is the same publicly trusted certificate class you'd use to sign an EXE or an MSI, so if you already sign Windows binaries, you're set.

    Here's the part most older tutorials get wrong. Since June 1, 2023, every publicly trusted code signing key has to be generated and stored on hardware certified to FIPS 140-2 Level 2 (or Common Criteria EAL 4+), and it must be non-exportable. There is no .pfx to copy onto a build box anymore. The key sits on a USB token, your own HSM, or a cloud signing service, and the certificate gets surfaced into your machine's certificate store — which is where the signer picks it up.

    Where a public code signing key may and may not liveTwo panels. On the left, a .pfx file on a build server is crossed out and labelled "not allowed for public certificates since June 2023". On the right, a USB token, an HSM, and a cloud signing service each surface the certificate into the machine's certificate store, where dotnet nuget sign reaches it by SHA-256 fingerprint.The old waycert.pfxon a serverNot allowed for publiccertificates since Jun 2023The way it works nowUSB tokenYour own HSMCloud signing serviceCertstoreSign by SHA-256 fingerprint
    The single biggest change to the workflow: there's no key file to hand the signer anymore, so you point it at a certificate the hardware or cloud service has surfaced into your store.

    If you don't have a certificate yet, a standard (OV) code signing certificate is enough for NuGet — you don't need EV for this. My-SSL issues code signing certificates through Certum with the hardware or cloud key delivery the current rules require. If you're weighing where that key should live before you buy, our comparison of cloud code signing versus USB tokens walks through the trade-offs for a shared or automated setup.

    Sign the package with dotnet nuget sign

    With the certificate in your store, sign the package by referencing it — not a file. The --certificate-fingerprint option finds the certificate in the store (default store name My) by its fingerprint, which is exactly how a hardware token or cloud service exposes it. From .NET 9 you pass a SHA-256 fingerprint; a SHA-1 fingerprint raises the NU3043 warning and, from .NET 10, is rejected as an error.

    # Sign using a certificate held on a token/HSM/cloud (surfaced into the store)
    dotnet nuget sign MyPackage.1.0.0.nupkg \
      --certificate-fingerprint <SHA-256 fingerprint> \
      --timestamper <your CA's RFC 3161 timestamp URL>

    For a private or test package whose key is a plain file, you can point at the certificate directly instead — but remember this path is not valid for public certificates:

    # Test/private only — file-based key, not allowed for public code signing
    dotnet nuget sign MyPackage.1.0.0.nupkg \
      --certificate-path cert.pfx \
      --certificate-password <password> \
      --timestamper <RFC 3161 timestamp URL>

    The older NuGet CLI uses the same ideas with PascalCase switches — nuget sign MyPackage.nupkg -CertificateFingerprint <hash> -Timestamper <url>. Signing overwrites the package in place with the signed version; use --output if you'd rather write the signed copy somewhere else.

    Timestamp so the signature outlives the certificate

    Always pass --timestamper. A timestamp is a trusted authority's signed proof of when you signed, and it's what keeps a package verifiable after the signing certificate expires. Without it, the signature is only trusted while the certificate is valid — and NuGet.org won't accept the upload at all, because it requires the primary signature to carry a single valid RFC 3161 timestamp.

    Use the RFC 3161 endpoint your certificate authority publishes; the timestamping certificate behind it must be valid for id-kp-timeStamping and use an RSA key of 2048 bits or more, which reputable CA timestamp services already meet. The mechanics are the same ones behind SignTool and jarsigner — our guide to code signing timestamps covers why a shipped build stays trusted for years while the certificate that signed it quietly expires.

    Verify the signature

    Before you push, confirm the signature is well-formed and trusted on the signing machine. dotnet nuget verify checks the author signature, its certificate chain, and the timestamp, and prints the certificate's fingerprint — the value you'll register on NuGet.org in the next step.

    # Verify the signature and print certificate details
    dotnet nuget verify MyPackage.1.0.0.nupkg --all
    
    # NuGet CLI equivalent
    nuget verify -Signatures MyPackage.1.0.0.nupkg

    A clean result lists your author signature with a valid chain and a timestamp. If it flags an untrusted chain, that's usually a missing intermediate certificate or a machine that doesn't trust the issuing root — fix it now rather than discover it on upload. For a private feed you control, you can pin the signer explicitly with dotnet nuget trust instead of relying on the machine's trust store.

    Register the certificate and publish to NuGet.org

    NuGet.org won't accept an author-signed package from an unknown certificate. First, on your NuGet.org account, open the package's or your account's certificate settings and register the signing certificate — by uploading it or entering its SHA-256 fingerprint. From then on, every version you publish must be signed by a certificate you've registered, which is what stops anyone else from impersonating your package ID.

    With the certificate registered, push as usual. NuGet.org verifies your author signature, confirms it matches a registered certificate, and then adds its own repository signature on top before serving the package.

    dotnet nuget push MyPackage.1.0.0.nupkg \
      --api-key <your-api-key> \
      --source https://api.nuget.org/v3/index.json
    Author signature versus repository signature on a NuGet packageA .nupkg shown with two nested signature layers. The inner author signature, made with your code signing certificate and a timestamp, proves the package came from you. The outer repository signature is added by NuGet.org after you upload, proving the package came through that feed.Repository signature — added by NuGet.org on upload"this package was served by this feed"Author signature — made by you"this package came from this publisher, unchanged"Package.nupkg+ RFC 3161 timestamp
    Your author signature and NuGet.org's repository signature answer different questions — who made it versus where it came from — which is why a package can safely carry both.

    Signing in CI/CD without exposing the key

    Automating this is where the hardware-key rule bites. Because there's no key file to drop into a pipeline secret, unattended signing means connecting the build to the hardware or cloud service that holds the key. A USB token can be plugged into a dedicated self-hosted runner; a cloud signing service authenticates from the pipeline and signs remotely; and tools like the open-source dotnet sign or an Azure Key Vault signer submit only a hash to the key and never move the private material.

    The design rules are the same across all three: the key never leaves its hardware boundary, the pipeline authenticates with a short-lived credential rather than an embedded secret, and only trusted branches can trigger a signing job. Our code signing in CI/CD guide lays out each pattern — self-hosted-runner token, cloud session, and pipeline-native service — and where each one fits.

    Where My-SSL fits

    You publish NuGet packages and need a code signing certificate that NuGet.org will acceptCode signing certificate
    You're deciding whether the key should sit on a token or in the cloudCloud signing vs USB tokens
    You want signing to run in your build pipeline without a key in a secretCode signing in CI/CD

    Common errors and fixes

    Most signing failures come down to the certificate, the chain, or a missing timestamp. Here are the ones that stop first attempts, and what each one is really telling you.

    • NU3001 — certificate not found or no code signing EKU. The fingerprint matched nothing in the store, or the certificate can't be used for code signing. Confirm the token or cloud provider surfaced the certificate into the right store and that its EKU includes id-kp-codeSigning.
    • NU3018 — chain could not be built or isn't trusted. Usually a missing intermediate certificate or a self-signed certificate. Install the full chain and make sure the certificate rolls up to a publicly trusted root; NuGet.org rejects self-signed signers outright.
    • NU3043 — SHA-1 certificate fingerprint. From .NET 9 a SHA-1 fingerprint warns; from .NET 10 it's an error. Pass the SHA-256 (or stronger) fingerprint instead.
    • Upload rejected: certificate not registered. NuGet.org won't accept an author-signed package until its certificate is registered on your account. Add the fingerprint in your account settings, then push again.
    • Upload rejected: missing or invalid timestamp. The signature has no valid RFC 3161 timestamp. Re-sign with --timestamper pointed at your CA's endpoint.

    FAQ

    Need the certificate that makes this work?

    Author signing only counts if the certificate chains to a publicly trusted root and its key sits on compliant hardware. My-SSL issues code signing certificates through Certum, a publicly trusted certificate authority, with the token, HSM, or cloud key delivery the current rules require — the same certificate signs your NuGet packages, EXEs, and installers.

    Related reading

    Sources worth checking directly

    • Microsoft Learn — Signing NuGet Packages and dotnet nuget sign (command syntax, fingerprint signing, SHA-1 deprecation)
    • Microsoft Learn — Signed Packages Reference (certificate and timestamp requirements, author vs repository signatures)
    • CA/Browser Forum — Baseline Requirements for Code Signing (hardware key rule and CSC-31 460-day validity)