Join our Newsletter — 33% off our NHI Course
Home› Guides› Package Registry Security Comparison Guide: npm, PyPI, Maven,…
Guide Software & AI Supply Chain

Package Registry Security Comparison Guide: npm, PyPI, Maven, NuGet, crates, RubyGems, Go

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 27 October 2026 13 min read
On this page

A polyglot organisation publishes to and consumes from several package registries, and each one offers different account, publishing, signing and namespace controls, so a single "secure our packages" policy is applied unevenly or not at all. npm, PyPI, Maven Central, NuGet, crates.io, RubyGems.org and the Go module ecosystem have converged on some ideas, notably OIDC-based trusted publishing and provenance, but they differ in what is mandatory, what is optional and what does not exist. This guide gives one comparative view for security architects, platform teams and open source programme offices: the controls each registry offers as checked on 27 October 2026, how to set a common baseline for publishing, how to configure consumption safely, and what to monitor. Registry features change often, so confirm the current documentation before relying on a specific detail.

Key takeaways

  • Trusted publishing is now the common baseline. npm, PyPI, NuGet, RubyGems.org and crates.io accept short-lived OIDC credentials from CI instead of long-lived API tokens; Maven Central and the Go ecosystem work differently.
  • Old tokens undo new controls. Turning on trusted publishing does not revoke existing API tokens; you must disable or delete them, as npm's "disallow tokens" setting is designed to do.
  • Signing models differ by ecosystem. Maven Central requires PGP signatures on every file, NuGet supports author and repository X.509 signatures, npm and PyPI use Sigstore-based provenance and attestations, and Go relies on a checksum database rather than signatures.
  • Namespace control is uneven. Maven Central verifies domain or account ownership, NuGet offers ID prefix reservation and npm has scopes; PyPI, RubyGems and crates.io use a flat name space where typosquatting defences are the registry's job.
  • Consumers carry half the risk. Hash-pinned lockfiles, an internal proxy or mirror, and verification of provenance or signatures are what protect you when a maintainer account is taken over.

A common yardstick: the OpenSSF principles

The OpenSSF Securing Software Repositories Working Group publishes Principles for Package Repository Security (v0.1, last updated February 2024), which grade registries from Level 0 to Level 3 across four tracks. It is the best neutral benchmark for comparing registries and for deciding what your own internal registry should offer.

TrackLevel 1Level 2Level 3
AuthenticationVerified email, documented recovery, TOTP MFA at minimum, alerts on security changes, brute force protectionPhishing-resistant MFA (WebAuthn) supported, MFA required for critical packages, leaked credential checks, abandoned email domain detectionPasskeys, MFA required for all maintainers, phishing-resistant MFA for critical packages
AuthorisationAPI tokens scoped to packages, registry-specific token prefixRole-based access for maintainersShort-lived tokens via OIDC (trusted publishers), tokens in secret scanning programmes, build provenance
GeneralVulnerability disclosure policy, typosquatting defencesUnpublish policy preventing version and name reuse, malware reporting and scanning, vulnerability warningsPeriodic security reviews, event transparency log, malicious package advisories in OSV format
CLI toolingInstall pinned by hash or versionWarn on known vulnerabilities at installProduce SBOMs, automated remediation, reachability analysis

Registry comparison: publishing controls

The table summarises publishing-side controls from each registry's own documentation, checked on 27 October 2026. "Trusted publishing" means the registry exchanges a CI provider's OIDC token for a short-lived upload credential.

RegistryTrusted publishingAccount and MFA controlsPublish-time integrity
npmYes: GitHub Actions (GitHub-hosted runners), GitLab.com shared runners, CircleCI cloud; self-hosted runners not supported. Needs npm CLI 11.5.1+ and Node 22.14.0+. Up to 10 trusted publishers per package2FA; per-package setting "Require two-factor authentication and disallow tokens"; staged publishing (npm stage publish) requires a maintainer to approve with 2FAProvenance attestations signed through Sigstore, generated automatically with trusted publishing from GitHub Actions and GitLab (not CircleCI, not private source repositories)
PyPIYes: GitHub Actions, GitLab CI/CD, Google Cloud, ActiveState; mints a short-lived project-scoped API token; "pending" publishers can create new projects2FA required for all accounts; project-scoped API tokensDigital attestations (PEP 740) using in-toto predicates SLSA Provenance and PyPI Publish, signed by trusted publisher identities
RubyGems.orgYes: GitHub ActionsMFA with WebAuthn recommended; MFA level "UI and API" covers push and owner changes; gems can set rubygems_mfa_required so every later version needs MFANo registry-wide signing requirement
crates.ioYes (RFC 3691): GitHub Actions first, with other providers planned in the RFC; access tokens valid for well under an hourSign-in via GitHub account; scoped API tokensNo registry signing requirement; checksums recorded in Cargo.lock
NuGet (nuget.org)Yes: GitHub Actions (NuGet/login action) and GitLab CI/CD; temporary API key valid for one hour, one OIDC token per key; new policies are provisional for 7 days until first publish binds repository and owner IDsScoped API keys; organisationsRepository signature applied by nuget.org; optional author signatures with X.509 code signing certificates
Maven CentralNo OIDC trusted publishing documented; publishing uses Central Portal user tokensNamespace must be verified before publishingEvery file must carry a .asc GPG/PGP signature plus .md5 and .sha1 checksums (.sha256/.sha512 optional); sources and javadoc JARs required
Go modulesNot applicable: no central upload; modules are fetched from source repositories through proxy.golang.orgDepends on the source host (for example GitHub account security)Checksum database records module hashes; versions are immutable once seen; authors can retract bad versions

Go is the outlier: there are no registry accounts to compromise, so the publishing risk moves entirely to the source repository and its tags. The Go Modules Reference explains that the go command verifies downloaded modules against go.sum and, for hashes not yet recorded, against the checksum database unless the module matches GOPRIVATE or GONOSUMDB. See the Go Vulnerability Management Guide.

Registry comparison: namespaces and consumption

RegistryNamespace controlConsumer integrity toolsSignature or provenance verification
npmScopes (@org/name) owned by users or organisationspackage-lock.json with integrity hashes; npm cinpm audit signatures checks registry signatures and provenance attestations
PyPIFlat names; registry handles typosquatting and malware reportspip install --require-hashes with hash-pinned requirements; lock toolsAttestations visible on PyPI and verifiable with Sigstore tooling
RubyGems.orgFlat namesGemfile.lockNo registry-wide verification path
crates.ioFlat namesCargo.lock checksumsNone at registry level
NuGetID prefix reservation: packages using a reserved prefix are rejected unless from its owners, with a visual indicator for reserved-prefix ownerspackages.lock.json with content hashessignatureValidationMode=require with trustedSigners for authors or repositories, optionally restricted to listed owners; tampered content fails with NU3008
Maven CentralVerified namespaces: DNS TXT record on the exact domain behind the groupId, or a code-hosting account (for example io.github.<user>)No native lockfile in Maven; Gradle dependency verification metadataPGP signature checks by build plugins; trust depends on key management
Go modulesModule path is the source repository URLgo.sum plus checksum databaseTransparency of the checksum database rather than signatures

For deeper per-registry guidance, see the npm Trusted Publishing and Provenance Guide, the PyPI API Tokens and Trusted Publishing Security Guide, the Maven Central and Gradle Supply Chain Security Guide, the NuGet Supply Chain Security Guide, the crates.io and Cargo Supply Chain Guide and the RubyGems Security Guide.

Setting one publishing baseline across registries

The aim is the same everywhere: no human-held or long-lived credential can publish, every release comes from a known pipeline, and consumers can verify where it came from.

  • Publish only from CI with trusted publishing: bind each package to one repository, one workflow file and, where supported, a protected deployment environment that requires approval. The OpenSSF guidance stresses that the OIDC token's audience must be registry specific (for example pypi or npm:registry.npmjs.org).
  • Remove the old path: after the first trusted publish, revoke all API tokens for the package and, on npm, select "Require two-factor authentication and disallow tokens". On registries without such a switch, delete the tokens and alert on any new token creation.
  • Use human approval where offered: npm staged publishing and protected CI environments add a second person between a merged change and a live release.
  • Phishing-resistant MFA for maintainers: WebAuthn security keys or passkeys for every owner account, with recovery codes stored securely.
  • Least privilege on owners: keep two to three owners per package, use organisation accounts and teams rather than personal ownership, and remove departed staff on the leaver date.
  • Provenance on by default: npm and PyPI generate provenance or attestations with trusted publishing from supported CI; for Maven, keep the signing key in an HSM or secrets manager used only by the release job. See the SLSA and Build Provenance Guide.
  • Harden the pipeline itself: trusted publishing moves the target to CI, so pin actions by commit, restrict id-token: write to the release job, and never let untrusted pull request input reach the publish job. See the GitHub Actions OIDC Federation Hardening Guide.

Consuming safely from every registry

  1. Route through an internal proxy: point all package managers at an internal repository manager that caches approved upstream packages, which gives you one place to block, quarantine and log.
  2. Prevent dependency confusion: reserve your internal names publicly where the registry allows (npm scope, NuGet prefix, Maven namespace), and configure clients so internal names resolve only from the internal source. See the Malicious Package and Dependency Confusion Guide.
  3. Commit hash-pinned lockfiles: install with the lockfile-enforcing command (npm ci, hash-checked pip installs, cargo build --locked, NuGet locked mode) in CI.
  4. Verify what can be verified: run npm audit signatures, enable NuGet signatureValidationMode=require for a defined set of trusted signers, keep Go checksum verification on and restrict GONOSUMDB to genuinely private modules.
  5. Delay new releases: a cooldown before adopting a newly published version lets registries and researchers remove malicious releases first. See the Dependency Update Automation Guide.

Rolling out the baseline

  1. Inventory: list every package, registry, owner account and existing token, including packages published years ago by individuals.
  2. Pilot one package per registry: configure trusted publishing, publish a pre-release from the pipeline, and confirm provenance or attestations appear on the registry page.
  3. Cut over: publish the next real release through the new path, then revoke tokens and switch on token restrictions.
  4. Test the failure case: attempt a publish with an old token or from a different workflow and confirm the registry rejects it.
  5. Roll back safely: if the pipeline breaks before a critical fix, issue a single short-lived, package-scoped token for that release and revoke it immediately after, rather than restoring the old long-lived token.
  6. Extend: repeat across all packages, then add consumer controls in CI and the internal proxy.

Decision guidance

  • Small team publishing a few packages: switch on trusted publishing, delete every token, enforce security key MFA on owners and stop there; that removes the most common takeover path.
  • Large organisation with many packages: manage registry organisations centrally, keep an inventory of every package and owner across registries, require trusted publishing by policy, and monitor registry audit events.
  • Registry without trusted publishing (Maven Central): store the portal token and signing key in a secrets manager, scope them to the release job, rotate on staff change, and alert on publishes outside the pipeline.
  • Choosing an internal registry product: score it against the OpenSSF levels, especially OIDC publishing, immutable versions and audit logs.

Detection and measurement

  • Unexpected publishes: compare each new version on the public registry against a pipeline run; a version without a matching run, or without provenance where you always generate it, is an incident trigger.
  • Account and token events: watch registry security emails and audit logs for MFA changes, new tokens, new owners and new trusted publisher configurations.
  • Name squatting: monitor registries for new packages similar to yours.
  • Consumer side: log proxy downloads of versions published within the last few days and block known malicious packages from OSV feeds.

Metrics:

  • Percentage of your published packages using trusted publishing with tokens disabled or deleted.
  • Number of active long-lived publishing tokens across all registries (target zero where trusted publishing exists).
  • Percentage of package owners with phishing-resistant MFA.
  • Percentage of releases with provenance, attestations or required signatures.
  • Percentage of builds installing from hash-pinned lockfiles through the internal proxy.

Framework mapping

FrameworkReferenceRegistry control
NIST SP 800-53 Rev. 5IA-2, IA-5Maintainer MFA, removal of long-lived publishing authenticators
NIST SP 800-53 Rev. 5SR-4, SR-11, CM-14Provenance, component authenticity, signed components
NIST CSF 2.0PR.AA-05, GV.SC-07Least privilege on package ownership; supplier risk from upstream packages
OWASP ASVS 5.0V15.1.2, V15.2.4Inventory from trusted repositories; transitive dependencies from expected repositories, no dependency confusion
MITRE ATT&CKT1195.001 Compromise Software Dependencies and Development Tools; T1078 Valid Accounts; T1528 Steal Application Access TokenMalicious releases from hijacked maintainer accounts or stolen publishing tokens

Common failure patterns

  • Trusted publishing beside a live token: in the Ultralytics PyPI compromise, two malicious versions came through the project's trusted publishing workflow after a crafted branch name injected code, and two more were uploaded with a long-lived API token never revoked after the move to trusted publishing.
  • Account takeover with no second factor on publish: the ua-parser-js npm hijack shows how one maintainer account can push malware to millions of weekly installs.
  • Registry account creation as an attack surface: in the GemStuffer RubyGems campaign, mass-created accounts and API keys issued to unverified accounts allowed thousands of malicious uploads in two days.
  • Unverified PGP signatures: Maven signatures prove only that someone with a key signed the file; consumers that never check which key signed it gain little.
  • Disabling Go checksum verification broadly: setting GONOSUMDB or GOFLAGS to skip verification for whole public hosts removes the main Go integrity control.
  • Same policy text, different reality: a policy saying "MFA on all registries" without per-registry evidence usually hides at least one registry where it is optional and off.

Practitioner checklist

  • Inventory every package you publish, on every registry, with owners and publishing method.
  • Enable trusted publishing wherever the registry supports it, bound to one workflow and a protected environment.
  • Revoke all long-lived publishing tokens afterwards and use npm's "disallow tokens" setting where available.
  • Require phishing-resistant MFA for every package owner and keep owner lists short.
  • Generate provenance or attestations on npm and PyPI, and protect Maven PGP keys in a secrets manager or HSM.
  • Reserve namespaces and prefixes for internal names on npm, NuGet and Maven Central.
  • Consume through an internal proxy with hash-pinned lockfiles and a release cooldown.
  • Verify signatures or provenance at install where tooling exists (npm audit signatures, NuGet trusted signers, Go checksum database).
  • Alert on publishes without a matching pipeline run and on new tokens or owners.

Standards and references

Related NHI Mgmt Group resources: npm Tokens Security Guide · RubyGems, NuGet and Crates.io Publishing Tokens Guide · Software Supply Chain Security Guide · Sigstore Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 27 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org