litellm - ✅(Solved) Fix [Security] Migrate PyPI publishing to Trusted Publishers (OIDC) to prevent token theft [1 pull requests, 4 comments, 5 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#24542Fetched 2026-04-08 01:27:12
View on GitHub
Comments
4
Participants
5
Timeline
7
Reactions
4
Author
Timeline (top)
commented ×4closed ×1cross-referenced ×1subscribed ×1

Following the supply chain attack on March 24, 2025, where malicious versions of litellm were published to PyPI, this issue proposes migrating all PyPI publishing workflows to use PyPI Trusted Publishers (OIDC-based authentication).

Root Cause

The attack was possible because the PYPI_PUBLISH_PASSWORD secret — a stored PyPI API token — was exfiltrated (reportedly via a compromised Trivy action). Once the attacker had the token, they could publish arbitrary packages to PyPI without any further authorization.

Any workflow that stores a PyPI API token as a GitHub secret is vulnerable to this class of attack. If a secret is exfiltrated through any means (compromised action, log leak, CI misconfiguration), the attacker gains full publish access.

Fix Action

Fixed

PR fix notes

PR #24543: fix(security): migrate PyPI publishing to Trusted Publishers (OIDC)

Description (problem / solution / changelog)

Summary

Closes #24542

Migrates all three PyPI publishing workflows from stored API tokens (PYPI_PUBLISH_PASSWORD / PYPI_ENTERPRISE) to PyPI Trusted Publishers (OIDC-based authentication).

This eliminates the attack vector used in the March 24 incident — there is no longer a stored token that can be stolen and used to publish malicious packages.

Changes

  • simple_pypi_publish.yml (main litellm package):

    • Removed TWINE_USERNAME env and TWINE_PASSWORD secret reference
    • Removed twine from installed dependencies
    • Added top-level permissions: id-token: write, contents: read
    • Added environment: pypi for deployment protection rules
    • Replaced twine upload step with pypa/gh-action-pypi-publish@release/v1
  • publish_enterprise.yml (litellm-enterprise package):

    • Added id-token: write to job permissions
    • Added environment: pypi-enterprise
    • Replaced twine upload with pypa/gh-action-pypi-publish@release/v1 (with packages-dir: enterprise/dist/)
  • publish_proxy_extras.yml (litellm-proxy-extras package):

    • Added id-token: write to job permissions
    • Added environment: pypi-proxy-extras
    • Replaced twine upload with pypa/gh-action-pypi-publish@release/v1 (with packages-dir: litellm-proxy-extras/dist/)

All existing build, version update, and non-publish steps are unchanged.

Admin Setup Required

Before merging, a PyPI project admin needs to configure Trusted Publishers on pypi.org. For each package:

  1. Go to pypi.org → the package → PublishingAdd a new publisher
  2. Configure the trusted publisher:
PackageWorkflowEnvironment
litellmsimple_pypi_publish.ymlpypi
litellm-enterprisepublish_enterprise.ymlpypi-enterprise
litellm-proxy-extraspublish_proxy_extras.ymlpypi-proxy-extras
  1. Create the corresponding GitHub environments (pypi, pypi-enterprise, pypi-proxy-extras) in repo Settings → Environments
  2. After verifying Trusted Publishers work, delete the PYPI_PUBLISH_PASSWORD and PYPI_ENTERPRISE secrets from GitHub repo settings

How It Works

Instead of authenticating with a stored API token, the workflow:

  1. Requests a short-lived OIDC token from GitHub (via id-token: write permission)
  2. Sends the OIDC token to PyPI
  3. PyPI verifies the token was issued by GitHub for the correct repo/workflow/environment
  4. PyPI authorizes the publish — no stored secret involved

References

Changed files

  • .github/workflows/publish_enterprise.yml (modified, +6/-6)
  • .github/workflows/publish_proxy_extras.yml (modified, +6/-6)
  • .github/workflows/simple_pypi_publish.yml (modified, +14/-14)
RAW_BUFFERClick to expand / collapse

Summary

Following the supply chain attack on March 24, 2025, where malicious versions of litellm were published to PyPI, this issue proposes migrating all PyPI publishing workflows to use PyPI Trusted Publishers (OIDC-based authentication).

Root Cause

The attack was possible because the PYPI_PUBLISH_PASSWORD secret — a stored PyPI API token — was exfiltrated (reportedly via a compromised Trivy action). Once the attacker had the token, they could publish arbitrary packages to PyPI without any further authorization.

Any workflow that stores a PyPI API token as a GitHub secret is vulnerable to this class of attack. If a secret is exfiltrated through any means (compromised action, log leak, CI misconfiguration), the attacker gains full publish access.

Proposed Fix: Trusted Publishers (OIDC)

PyPI Trusted Publishers eliminate stored tokens entirely. Instead, GitHub Actions authenticates directly with PyPI via OpenID Connect (OIDC):

  • No token to steal — there is no PYPI_PUBLISH_PASSWORD secret at all
  • Cryptographically scoped — PyPI verifies the OIDC token came from a specific GitHub repo, workflow file, and environment
  • Short-lived — the OIDC token is valid only for the duration of the workflow run
  • Auditable — PyPI logs which workflow and commit triggered each publish

This is the approach recommended by PyPI and used by most major Python packages.

Affected Workflows

All three PyPI publish workflows currently use stored API tokens:

WorkflowSecret UsedPackage
simple_pypi_publish.ymlPYPI_PUBLISH_PASSWORDlitellm
publish_enterprise.ymlPYPI_ENTERPRISElitellm-enterprise
publish_proxy_extras.ymlPYPI_PUBLISH_PASSWORDlitellm-proxy-extras

Required Changes

1. PyPI Admin Setup (one-time, per package)

For each package (litellm, litellm-enterprise, litellm-proxy-extras):

  1. Go to pypi.org → the package → PublishingAdd a new publisher
  2. Configure:
    • Owner: BerriAI
    • Repository: litellm
    • Workflow name: the respective .yml file
    • Environment: the respective environment name (pypi, pypi-enterprise, pypi-proxy-extras)
  3. Save

2. Workflow Changes

  • Remove TWINE_USERNAME / TWINE_PASSWORD environment variables
  • Add permissions: id-token: write for OIDC token requests
  • Replace twine upload with pypa/gh-action-pypi-publish@release/v1
  • Add environment: to each job for deployment protection rules

3. Cleanup

After Trusted Publishers are configured and verified:

  • Delete the PYPI_PUBLISH_PASSWORD secret from GitHub repo settings
  • Delete the PYPI_ENTERPRISE secret from GitHub repo settings

References

extent analysis

Fix Plan

To migrate to PyPI Trusted Publishers, follow these steps:

  1. PyPI Admin Setup:

    • For each package, go to pypi.org → the package → PublishingAdd a new publisher
    • Configure:
      • Owner: BerriAI
      • Repository: litellm
      • Workflow name: the respective .yml file
      • Environment: the respective environment name (pypi, pypi-enterprise, pypi-proxy-extras)
  2. Workflow Changes:

    • Remove TWINE_USERNAME / TWINE_PASSWORD environment variables
    • Add permissions: id-token: write for OIDC token requests
    • Replace twine upload with the following GitHub Action:
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
    • Add environment: to each job for deployment protection rules
  3. Example Workflow:

    name: Publish to PyPI
    on:
      push:
        branches:
          - main
    jobs:
      publish:
        runs-on: ubuntu-latest
        environment: pypi
        permissions:
          id-token: write
        steps:
          - name: Checkout code
            uses: actions/checkout@v3
          - name: Set up Python
            uses: actions/setup-python@v4
          - name: Publish to PyPI
            uses: pypa/gh-action-pypi-publish@release/v1
  4. Cleanup:

    • Delete the PYPI_PUBLISH_PASSWORD secret from GitHub repo settings
    • Delete the PYPI_ENTERPRISE secret from GitHub repo settings

Verification

To verify the fix, check the following:

  • The workflows are successfully publishing packages to PyPI without using stored API tokens.
  • The PyPI logs show which workflow and commit triggered each publish.
  • The PYPI_PUBLISH_PASSWORD and PYPI_ENTERPRISE secrets are deleted from the GitHub repo settings.

Extra Tips

  • Regularly review and update the PyPI Trusted Publishers configuration to ensure it remains secure and up-to-date.
  • Consider implementing additional security measures, such as two-factor authentication and access controls, to further protect the PyPI publishing workflows.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING