|
| 1 | +--- |
| 2 | +title: Token Exfiltration Campaign via GitHub Actions Workflows |
| 3 | +description: Incident report of a recent attack campaign targeting GitHub Actions workflows to exfiltrate PyPI tokens, our response, and steps to protect your projects. |
| 4 | +authors: |
| 5 | + - miketheman |
| 6 | +date: 2025-09-16 |
| 7 | +tags: |
| 8 | + - security |
| 9 | + - transparency |
| 10 | +--- |
| 11 | + |
| 12 | +## Summary |
| 13 | + |
| 14 | +I recently responded to an attack campaign where malicious actors injected code into GitHub Actions workflows |
| 15 | +attempting to steal PyPI publishing tokens. |
| 16 | +PyPI was not compromised, and no PyPI packages were published by the attackers. |
| 17 | + |
| 18 | +Attackers targeted a wide variety of repositories, many of which had PyPI tokens stored as GitHub secrets, |
| 19 | +modifying their workflows to send those tokens to external servers. |
| 20 | +While the attackers successfully exfiltrated some tokens, they do not appear to have used them on PyPI. |
| 21 | + |
| 22 | +I've invalidated all affected tokens and notified the impacted project maintainers. |
| 23 | +If you're one of them, I have emailed you from <[email protected]>. |
| 24 | + |
| 25 | +<!-- more --> |
| 26 | + |
| 27 | +You can read more about the details of the attack on [GitGuardian's blog](https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen/). |
| 28 | + |
| 29 | +## Timeline and Response |
| 30 | + |
| 31 | +On September 5th, a GitGuardian employee used the [PyPI "Report as malware" button](./2024-03-06-malware-reporting-evolved.md) |
| 32 | +to submit their findings for a project named `fastuuid` - namely they found a malicious GitHub Actions workflow |
| 33 | +attempting to exfiltrate PyPI tokens to a remote server. |
| 34 | +No compromise on PyPI was found, tokens relating to the user accounts were invalidated, |
| 35 | +and I reached out to the project owners to notify and help secure the account and project. |
| 36 | + |
| 37 | +Later on September 5th, another researcher from GitGuardian emailed PyPI Security |
| 38 | +directly about their current findings, effectively an expansion of the previous attack. |
| 39 | +Due to some of the contents in that email, it ended up in our inbound Spam folder, |
| 40 | +delaying response until September 10th when I became aware of the attack via other channels, |
| 41 | +and found the original email in the Spam folder. |
| 42 | +I may follow up with our support system provider to see about improving spam filtering rules. |
| 43 | + |
| 44 | +After triaging the situation, I discovered another Indicator of Compromise (IoC) in the form of a URL, |
| 45 | +which I shared with GitGuardian to assist with their ongoing investigation. |
| 46 | + |
| 47 | +Over the course of the following few days, I reviewed the findings from the researchers. |
| 48 | +I observed that many of the project maintainers responded to notifications from the researchers on their open source issue trackers, |
| 49 | +either reverting the changes to their actions workflows, |
| 50 | +or removing the affected workflows entirely from history via force-push of the repository. |
| 51 | +Many of the maintainers also proactively rotated their PyPI tokens. |
| 52 | + |
| 53 | +After confirming that no PyPI accounts had been compromised, |
| 54 | +on September 15th I reached out to the maintainers of the affected projects to notify them of the situation, |
| 55 | +to let them know that their tokens had been invalidated, |
| 56 | +and recommend using [Trusted Publishers](https://docs.pypi.org/trusted-publishers/) |
| 57 | +with GitHub Actions to help protect their projects in the future. |
| 58 | + |
| 59 | +## What You Can Do |
| 60 | + |
| 61 | +If you use GitHub Actions to publish to PyPI, I recommend the following steps to protect your projects: |
| 62 | + |
| 63 | +1. Replace long-lived tokens with [Trusted Publishers](https://docs.pypi.org/trusted-publishers/. |
| 64 | + This is the most effective way to protect your projects from this type of attack. |
| 65 | + GitHub Trusted Publishers use short-lived tokens that are scoped to a specific repository, |
| 66 | + and expire after a short period of time. |
| 67 | +2. Log into your account and review your security history for any suspicious activity. |
| 68 | + You can do this by going to your [Account Settings](https://pypi.org/manage/account/) |
| 69 | + and scrolling to the ["Security History" section](https://pypi.org/manage/account/#account-events). |
| 70 | + |
| 71 | +While Trusted Publisher tokens can still be exfiltrated, |
| 72 | +using Trusted Publishers significantly reduces the risk of compromise. |
| 73 | + |
| 74 | +## Acknowledgements |
| 75 | + |
| 76 | +Thanks to Charles Brossollet, Guillaume Valadon, and Gaëtan Ferry |
| 77 | +of [GitGuardian](https://www.gitguardian.com/) for their collaboration on this issue. |
| 78 | + |
| 79 | +This investigation and incident response is made possible by the generosity of individuals and corporations |
| 80 | +supporting critical security efforts to better secure the Python community, |
| 81 | +with thanks to [Alpha-Omega](https://alpha-omega.dev/). |
| 82 | + |
| 83 | +Support these efforts and more here: <https://www.python.org/sponsors/application/> |
0 commit comments