Eliminating long-lived credentials with trusted publishing
Trusted publishing is an authentication mechanism that relies on short-lived credentials to reduce the risk of supply-chain attacks. At the 2026 Open Source Summit North America, Mike Fiedler walked the audience through why trusted publishing exists, how it works, and made the case for its adoption. It is not a silver bullet against all attacks, but it does offer protection against theft of long-lived credentials used to publish to package registries.
Fiedler is employed by the Python Software
Foundation (PSF) as the safety and security engineer for the Python Package Index (PyPI). This is a
role, he said, that did not exist before he took the job three years
ago. It exists thanks to funding from the Linux Foundation's Alpha-Omega initiative. Everything he would be
covering in his talk, he said, exists "pretty much because somebody
is paid full time to think about these things
".
He asked whether the audience was familiar with PyPI, or if they had ever installed anything using pip. Most, if not all, of the hands in the room were raised at that point. Fiedler said that he had asked if anyone knew about PyPI at a data-science conference and got blank faces; but when he asked if they had ever used pip install, everyone raised their hand.
Scale
They are not alone. PyPI serves more than 13 billion requests per
day, Fiedler said, adding "which is a lot
" with a smile. More
than 900 projects are created on PyPI each day; that number does not
include all of the existing projects that publish releases each
day. The site serves 10 petabytes of traffic a day, with a peak of 1TB
per second. There are more than one million user accounts on the site,
as well, to support publishing packages. "The blast radius here is
kind of big, right?
"
He said that "everybody depends on some other dependency, and
that dependency depends on another dependency
", which meant that
even small, incremental improvements in any part of the PyPI ecosystem
meant it would have a major impact on the rest of the
ecosystem. "Every little step counts
". Trusted publishing is,
he said, one of the more materially useful steps that one can do.
More than 2.2 million files have been published using the trusted
publishing method since it was first
offered to PyPI package maintainers in April 2023. He said that
trusted publishing was used for about 10% of all new uploads in
February 2024, and for more than 36% of new uploads as of May 2026.
"So it's not a hockey stick directly into, like, 80% or 90%. It is
more of a slow roll because a lot of people are unfamiliar with this
new idea, and their old systems still work.
" It will require
educating people, he said, on why they should want to use trusted publishing, make
it easy to adopt, "and then see the benefits echo through the
ecosystem.
"
"Password with a nice hat"
"Let's start with the release-day ritual
", Fiedler said.
To publish a project to the package registry, a user needs to have an
have an API token to
authenticate and upload packages to PyPI. That token may be stored on
someone's laptop in a .pypirc file, if they run the release
from that computer. The token might be stored on GitHub so that the
user can use GitHub
Actions to publish to
PyPI, or it may be stored with another continuous-integration/continuous-delivery
(CI/CD) provider. The common thread, he
said, was that these tokens "live forever until you decide to
delete them
" and they will continue to live on disk somewhere
indefinitely.
A long-lived API token "is basically a password with a nice
hat
", he said. "Nothing about the word 'token' is particularly
protecting you. It's just a password.
" And, because people make
mistakes, it can be exfiltrated, phished, logged, or committed to
code—just like a password can be.
A token could be exposed in any number of ways; it might
be accidentally committed to a Git repository, or it might show up in
CI/CD logs. People are targeted with phishing attacks all the time, he
said, "and some people fall for it. It happens, right?
"
Maintainers click links that they are told to click "because they
trust the ecosystems that are sending them those links
", and
because they are often overburdened and just trying to do their
work.
15 minutes of trust
With trusted publishing the token is issued at publication time,
rather than being stored somewhere. Users first have to set
up a trusted publisher for their project. They have to supply the
names of the GitHub owner (organization or user), repository, and
workflow file (e.g., release.yml), and (optionally) an environment
name. Fiedler described environment as "an extra security
gate
" that allowed a project to configure, for instance, which
people are allowed to trigger a release.
Then, when a user starts the publishing process, their CI (such as GitHub Actions) asks for an OpenID Connect (OIDC) identity token from GitHub's OIDC provider. Then GitHub grants a signed JSON Web Token (JWT) with the four strings that indicate the owner of the project, the repository it is coming from, the workflow file, and environment if it's configured.
PyPI only issues a token if all four match. For example, if a package is configured for trusted publishing by user "jzb" on GitHub, PyPI will not issue a token if the publishing process is initiated by a different user—even if it is still coming from the same repository and workflow file. If someone forks a repository, or renames it, then no token will be issued because the repository won't match.
The GitHub Actions job then sends the JWT token to PyPI. If it has a
matching record for the token, PyPI will then issue an API token that
is set to expire in 15 minutes. Why 15 minutes? Fiedler said that
duration was chosen because some larger projects may have multi-step
release flows, have a lot of data to upload to PyPI, or may be
building for a number of different platforms. "Your build process
takes the API token, performs the upload. Everything is copacetic. The
token disappears.
"
The token is not stored long-term and "isn't a ticking time
bomb that's just sitting around waiting for somebody to consume
it
". Before trusted publishing, the token lived forever just
waiting to be exposed somehow. Some organizations may have security
policies that require changing tokens at a regular interval, but that
still happens more slowly and might be forgotten. Trusted publishing
does not depend on manual processes: "Once you set it up, you
literally can forget this, and the system will continue to operate in
the manner so far that we have found secure.
"
He noted that some of the error messages when trusted publishing
fails are "a little opaque
", and encouraged people to open an
issue if they run into problems. "We'll try to live debug it, so
that way we can improve these error messages and workflows for folks
in the future.
"
Fiedler used a GitHub project as an example during the talk, but
PyPI's trusted publishing currently
supports four identity providers: GitHub, GitLab, Google Cloud,
and ActiveState. Support for self-managed GitLab instances is
in beta, and he said that work is underway to support CircleCI as a provider as well.
He said that PyPI pioneered trusted publishing, but there are
now six package repositories that enable trusted publishing: crates.io, npm, NuGet,
Packagist,
and RubyGems
also have support for the feature. "We've seen a massive
adoption. We've showed the community. We share. We work with other
communities. And they followed suit.
"
Case studies
Fiedler said that he would walk through some recent attacks that took advantage of long-lived tokens. He began with the Ultralytics project, which suffered a supply-chain attack in December 2024. A malicious pull request, he said, contained code that tricked GitHub Actions into running attacker-controlled code with a privileged secret, using pull_request_target. Ultralytics was using trusted publishing, but the project was not using the environment feature that could have required approval from a designated GitHub maintainer prior to publishing.
He advised people to audit their GitHub Actions workflows and
see if they were using pull_request_target. If so, they
should stop; it was meant for behind-the-firewall enterprise usage,
rather than for open-source projects, and he said most people who were
using it were doing so insecurely. "It's a very sharp tool that
will, if you pick it up, it will cut you. So try to avoid using that
if you can.
"
That was the case with Ultralytics, and it allowed attackers to publish
several releases with crypto-mining malware. The silver lining, he
said, was that Ultralytics was using trusted publishing so researchers
and PyPI staff were able to find the exploit quickly. Another example
that people may have heard of, he said, is the Shai-Hulud
worm. He was upset that the attackers used the name, "because I
love Dune, and they've co-opted the most majestic sandworm into an
annoying malicious attack
". It is a self-propagating worm that
compromised hundreds of npm
packages within hours of its launch.
PyPI sidestepped it for a long time, Fiedler said, because it was
not the target for the attackers. However, there were repositories
that had projects that publish to both npm and PyPI. While the attackers were
targeting npm tokens, they also picked up a long-lived PyPI token
"and then we saw some lateral movement into the PyPI
ecosystem
". Because it happened to PyPI at a smaller scale than
npm, Fiedler said, he was able to work directly with affected
maintainers to help them with recovery and notifying the world that
they'd been exploited. "I could not do that at the scale that they
had attacked the npm ecosystem
."
Fiedler also spoke about the LiteLLM and Telnyx supply-chain attacks. These projects were compromised through a dependency on the Trivy vulnerability scanner, which is provided as an npm package, that was exploited and used to attack a number of other open-source repositories. That exploit chain allowed attackers to exfiltrate long-lived tokens from LiteLLM and Telnyx. He said that attackers may not go directly for popular projects: they will attack the dependencies of the popular projects. Developers should pin their dependencies so that compromised versions are not pulled in automatically as an accidental upgrade.
Attack categories disappear
The pattern is clear in each attack: "somebody had a long-lived
token, somebody else got it
". The answer to that is to use trusted
publishing to do away with long-lived tokens. With trusted publishing,
the credential does not exist outside of the provider (such as
GitHub), and there is no long-lived token to be stored. "So trust
the pipeline, not the password.
"
When a project is using trusted publishing, he said, "the threat
model changes completely
". An entire class of problems goes
away. There is no token to commit to Git. The token will be
obfuscated in any CI log, as well, Fiedler said. It's possible that it could
accidentally be sent to a log, but "because GitHub and GitHub
Actions now know the format of our token, they will obfuscate that by
default. They'll redact it
." People can still be subjected to
phishing attacks, he said, but the tokens are removed from the
equation. "So entire attack categories just fall off the map, and we
can worry about this particular vector less.
"
If Ultralytics had been using trusted publishing [with the environment feature], he said, the
publishing workflow would have still run; however, the pull-request
branch would not match the workflow reference, so PyPI would not have
issued a token. "There's a publisher record on PyPI. You can't
steal that.
"
Artifacts published with trusted publishing also include a
provenance receipt in the form of a Sigstore signature. That, Fiedler
said, can be used to validate whether a package went through the
trusted publishing path or if it was tampered with along the
way. There is a project called pypi-attestations
that can be used to verify packages, but verification is not built
into the package managers yet. "They're still talking about how that
should happen.
" He encouraged those with ideas and time to
contribute to pitch in, or to help fund work so that downstream users
could easily validate the attestations. Homebrew, he said,
already validates
Sigstore attestations.
Attestation is a hard concept for most people who aren't security
experts to wrap their heads around, he said. PyPI is working through
how to display attestation information to users in a way that is
"not too scary, not too promising that this is 100% secure, because
all we're saying is that this was not tampered with in
flight
". There could still be code that users do not want in a
package, "we're not saying what's inside is good for you
", but
that is a different problem. Attestations merely show that no
one has messed with the publishing pipeline; they do not guarantee
that something hasn't gone awry at another stage.
Delete the old token
Even if a project has set up trusted publishing, there is one step
that remains: delete the old token. "It is still just as viable as
the day that it was minted.
" There are still some instances when
an API token is the right call, he said, such as brand-new releases
from new projects. "You haven't set up CI/CD yet. You're just
piloting something out on your project. You don't have any users.
"
In that case, it's reasonable to publish something from a laptop. Once it is
done and people are downloading it, though, it is time to increase the
security of the project.
Another scenario where API tokens are still useful is if a project
is not using a registry or ecosystem that has trusted publishing
support. "But you should be asking your registries, or your CI/CD
providers, how come you don't support this? Please support a more
secure methodology.
"
Fiedler said that it might also make sense to use an API token when
there is a need to do a manual release or a rush release, such as a
hotfix or a critical security release. If a project has been using
trusted publishing, "you will set off every security scanner that
has been monitoring the project
", but it might be necessary in
some cases. However, if a project does create a regular API token, he
asked that the project please invalidate it immediately after use. "Try to
kill it as soon as you can.
"
He encouraged people who maintain projects to start adopting
trusted publishing. "Delete one [token] this week. Try it. If it
doesn't work for you, please let us know. But kill off one token this
week.
" He also reiterated that his role was funded by Alpha-Omega,
which takes donations. "If you work for a company that enjoys using
Python, please help the world by funding us.
"
Questions
During the Q&A, I noted that all of the providers that are
supported are corporate entities, and asked whether there
were plans to support community projects such as Forgejo which do not have the same
kind of funding and resources. Fiedler said that they had gotten a lot
of that kind of request lately, "like, how do we support
Forgejo?
" He noted that there is an open
thread on the Python forum that talks about providers like
Forgejo, and the steps that they would need to take "in order for
us to be comfortable with their security stance and posture, to be
able to onboard [them]
".
The ecosystems that are supported are
well-funded and have time to work on supporting trusted publishing.
"When Forgejo gets to that point where they have enough security
operations done, I think we would love to entertain bringing them
in because a lot of people want to use that, and we want to support
them.
" Until then, users on Forgejo and other platforms will have
to continue using long-lived tokens.
Another attendee asked "what happens when you want to transfer
the project to somebody else or when you want to rename the
project?
" The right way to handle that, he said, was to remove the
existing trusted publishing configuration and re-enroll with the new
data.
Fiedler's slides have been published on his web site. The video for the session is available on the Linux Foundation's YouTube channel.
[Thanks to the Linux Foundation, LWN's travel sponsor, for funding my travel to Minneapolis to attend the Open Source Summit.]
The LWN site is currently under high scraper load, so comment display has been suppressed for anonymous users. If you are a human, you may read the comments by clicking the button below:
Note: you can avoid this step in the future by logging into your LWN account.
