|
|
Log in / Subscribe / Register

Eliminating long-lived credentials with trusted publishing

By Joe Brockmeier
June 9, 2026

OSSNA

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

[Mike Fiedler]

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.


Copyright © 2026, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds