You shouldn't trust Trusted Publishing

35 points by yossarian a day ago on lobsters | 20 comments

ENOSUCHBLOG

Programming, philosophy, pedaling.


Jul 7, 2026     Tags: oss, python, security    


…because Trusted Publishing isn’t for you (or me) to trust! It’s for the machines.

Trusted Publishing is an authentication scheme that involves machine-to-machine trust. If you find yourself arguing (or for!) against Trusted Publishing on the basis that you (a human) can’t (or can) trust it then you’re making a category error, one that PyPI is careful to help you not make.

I wrote about this indirectly about two years ago, but I left this observation implicit rather than laying it out explicitly. This is an attempt to correct that mistake.

Quick recap#

“Trusted Publishing” is a term of art that PyPI uses to describe a form of authentication on top of OpenID Connect (OIDC) federation. PyPI released it in 20231, and it’s since been adopted widely by other packaging ecosystems (including npm, RubyGems, crates.io, and NuGet).

The basic observation behind Trusted Publishing is twofold:

  1. Long-lived credentials (like index API tokens) are difficult to secure, and are often over-scoped because users find it frustrating to determine the “right” minimal scope and expiry. Consequently, the impact of a compromised or leaked credential can be much broader than the specific system it was stolen from.
  2. Many users provision credentials solely for the purpose of putting them in a CI/CD platform, which they then publish from. However, CI/CD platforms often also have identity mechanisms that allow a user to demonstrate control of a specific machine identity2 via OIDC.

Trusted Publishing combines these into an authentication scheme: the user performs a one-time registration of their “Trusted Publisher” (their CI/CD machine identity) with their package index. Then, whenever the CI/CD presents an identity token, the package index verifies it and issues a corresponding, minimally scoped, short-lived publishing credential.

This can be hard to visualize; Seth Larson’s diagram is instructive:

A visualization of the Trusted Publishing enrollment and issuance flows. (Source: OpenSSF)

Broadly speaking, this approach to short-lived, self-scoping credentials has been a huge success: we’ve found that users3 prefer not to manually manage credentials when they don’t have to, and that large Open Source projects and companies alike both like the property of their publishing being tied to their source identity rather than any individual project maintainer.

Of course, Trusted Publishing is not perfect: it has a complicated data model4, requires bespoke treatment for each OIDC provider that an index chooses to support5, and (of course) can still be compromised (since, at the end of the day, it’s still an authentication scheme and there needs to be a credential somewhere in the flow)6.

Despite these qualifications, I think Trusted Publishing has been a net win for packaging ecosystems that adopt it. As mentioned in the earlier post, security is a matter of identifying and protecting the areas where your users congregate their trust (their “watering holes”), and Trusted Publishing accomplishes that by reducing the number of long-lived, over-scoped credentials that users are exposed to.

What of trust?#

Thus far, everything I’ve written makes Trusted Publishing sound pretty good, if not a silver bullet.

So, why the emphasis on not trusting it?

This is an important subtlety: Trusted Publishing is just an authentication method. The only thing Trusted Publishing does is establish a trust relationship between an external machine identity (like a CI/CD workflow) and a package identity on an index for the purpose of authenticating an upload; it does not tell a user that a package is safe to use, high quality, or anything else.

You can prove this to yourself easily: PyPI is a public index (by design), which means that anybody can upload to it, and anybody can use a Trusted Publisher to upload7. Because anybody can use one, they can be used to upload anything, including malware or vulnerable code. They are exactly like API tokens (PyPI’s other upload authentication method) in this regard.

PyPI is very careful8 to not mislead users into believing that they can or should trust a package based on its Trusted Publishing status. If you go to a project’s page on PyPI, you’ll notice that there is no “magic green checkmark” signaling a project’s Trusted Publishing status.

Using zizmor as an example:

A screenshot of zizmor's latest release on PyPI

Observe that the only “green checkmark” for user-controlled state on this page is for links that PyPI can prove came from the same source as the package itself. These links, too, are intentionally not described as “trusted”; as the PyPI docs explain:

A URL being verified only attests that the URL is under control of the PyPI package owner at the time of verification, and does not imply any additional safety about that URL or any other relationship to the project in question.

If you do want to see the Trusted Publishing status of a particular file on PyPI you’ll need to dig for it. You’ll find it ignominiously rendered as a simple “Yes/No” deep in the file details:

I say “ignominiously” because you can see how little effort has been placed into rendering the “file metadata” section, because it’s not important trust information. We don’t even bother to properly render the blob of JSON that comes from the uploading client’s user agent!

Here, too, you can see that no normative statement of trust is applied to the Trusted Publishing status: there’s a boolean state, and nothing whatsoever to imply that a user can or should trust a project more or less because of that state.

Summary#

Trusted Publishing is a mechanism for establishing trust between an external machine identity (like a CI/CD workflow) and one or more projects on a package index/registry. The “trust” in “Trusted Publishing” refers to that trust relationship, and not to anything else.

It is not, and cannot be, a signal for package trust or quality. You cannot use it to determine whether a package is safe or “good,” and PyPI consciously stymies attempts to misuse it for that purpose by not rendering it as a “green checkmark” or anything else of the sort.

Or as another framing: Trusted Publishing is just a form of authentication. It doesn’t tell you anything other than that an upload was authenticated, which all uploads to PyPI are.

With apologies to Anatole France:

Trusted Publishing, in its majestic equality, permits seasoned maintainer and script kiddy alike to publish malware, to release slop for HN karma, and to obtain security advisories for embarassing flaws.

Afterword#

This post is about Trusted Publishing, not attestations. Attestations are a technically distinct topic on PyPI that (currently) also use OIDC machine identities, but are simiarly not a signal of trust.

To analogize: an attestation is effectively a signature on top of a machine identity, but anybody can upload to PyPI and therefore anybody can sign with any machine identity they control. The presence of an attestation is not guaranteed by the presence of a Trusted Publisher, and similarly does not imply any particular end-user trust until you separately establish trust in that identity.

This, too, is explicitly documented.