Skip to content

Commit d501dd6

Browse files
committed
fix: more typos and redundancies
1 parent de45078 commit d501dd6

File tree

1 file changed

+16
-53
lines changed

1 file changed

+16
-53
lines changed

_posts/2024-12-13-python-packaging-security.md

Lines changed: 16 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,23 @@ comments: true
1616
last_modified: 2024-12-13
1717
---
1818

19-
2019
## Is your PyPI publication workflow secure?
2120

22-
The recent Python package breach [involving Ultralytics](https://blog.yossarian.net/2024/12/06/zizmor-ultralytics-injection) has spotlighted the importance of securing your Python package PyPI publishing workflows. The Ultralytics breach was a supply chain attack where malicious actors exploited a GitHub workflow to inject harmful code into a Python package, enabling them to hijack users’ machines for Bitcoin mining. What this means in English:
23-
24-
> The Ultralytics breach happened when hackers tricked a Python package into running bad code, letting them use other people’s computers to mine Bitcoin without permission.
25-
26-
Yikes!
27-
28-
todo: just say no to bitcoin mining graphic
21+
The recent Python package breach [involving Ultralytics](https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/) has highlighted the need for secure PyPI publishing workflows. Hackers exploited a GitHub workflow (`pull_request_target`) to inject malicious code, which was published to PyPI. Users who downloaded the package unknowingly allowed their machines to be hijacked for Bitcoin mining.
2922

23+
> Hackers tricked a Python package into running bad code, using other people’s computers to mine Bitcoin without permission. Yikes!
3024
31-
As open source maintainers, it’s unsettling to consider that our package users could become vulnerable to breaches like this.
32-
33-
34-
However, there’s a silver lining. In this case, the incredible PyPI security team had already addressed most of the issues that led to the Ultralytics breach. This incident highlights a gap in understanding of Python packaging security best practices.
25+
While unsettling, there’s a silver lining: the PyPI security team had already addressed most of the issues that caused this breach.
3526

3627

3728
{% include pyos-blockquote.html quote="Because the Ultralytics project was using Trusted Publishing and the PyPA’s publishing GitHub Action: PyPI staff, volunteers, and security researchers were able to dig into how maliciously injected software was able to make its way into the package." author="Seth Larson, PSF Security Expert" class="highlight magenta" %}
3829

30+
This incident underscores the importance of understanding Python packaging security best practices.
3931

40-
This makes sense--we love open source but can't be experts in everything.
32+
In this blog post, we'll cover the lessons learned that you can apply - TODAY - to your own Python packaging workflows!
4133

42-
## Takeaways
34+
<div class="notice" markdown="1">
35+
## TL&DR Takeaways
4336

4437
The Ultralytics breach is a wake-up call for all maintainers: secure your workflows now to protect your users and the Python ecosystem. Start with these key actions:
4538

@@ -57,28 +50,7 @@ The Ultralytics breach is a wake-up call for all maintainers: secure your workfl
5750
- 📱 Enable 2FA for your PyPI account and store recovery codes securely.
5851

5952
These steps will significantly reduce risks to your packages, contributors, and the broader Python ecosystem. Don’t wait—start securing your workflows today.
60-
61-
### What happened in the Ultralytics breach?
62-
63-
The Ultralytics incident was a **supply chain attack**—a type of attack where sneaky coders compromise the tools or processes used to create or distribute software. In this case, the bad actors/hackers wanted to use the user's machines to mine Bitcoin. This was a hack with the goal of using other people's compute for illegal profit!
64-
65-
In this case:
66-
67-
- An attacker exploited a GitHub action's trigger (`pull_request_target`) to inject malicious dependencies into the project.
68-
- This code was then published to PyPI
69-
- When a user downloaded and installed the package, their local machine was compromised.
70-
71-
**Yikes!**
72-
73-
TODO: image meme of someone's head exploding
74-
75-
The root cause of the breach was actually:
76-
77-
* A GitHub action workflow configuration that granted publish permissions to pull requests, allowing the attacker to execute unauthorized actions.
78-
* A leak of the repositories' PyPI token (likely through GitHub secrets).
79-
* A user (or bot?) gained direct access to the repo itself to push changes to the build that had previously provided some level of security around who could kick off a build that was published to PyPI.
80-
81-
If you want more details about what happened, [you should check out Seth Larson's PyPI blog post on the event](https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/), Seth is the resident security expert for the PSF and Python.
53+
</div>
8254

8355

8456
## A call to action if you are publishing to PyPI using GitHub actions
@@ -87,7 +59,7 @@ What's important for us is that this event highlights the need for our ecosystem
8759

8860
For this post, we will use [this workflow that pyOpenSci has setup](https://github.com/pyOpenSci/pyosMeta/blob/main/.github/workflows/publish-pypi.yml) that was reviewed and developed by both a PyPI maintainer and also several core pyOpenSci community members that have significant knowledge about best practices in publishing to PyPI.
8961

90-
Below, are actionable steps you can take to enhance security when publishing Python packages to PyPI using GitHub actions.
62+
Below are actionable steps you can take to enhance security when publishing Python packages to PyPI using GitHub actions.
9163

9264

9365
## 1. Avoid `pull_request_target` and consider release-based workflows
@@ -176,7 +148,6 @@ jobs:
176148
...
177149
```
178150

179-
180151
## 4. Use Trusted Publisher for PyPI
181152

182153
If you only [publish locally to PyPI using the command line](https://www.pyopensci.org/python-package-guide/tutorials/publish-pypi.html), you need to use a PyPI token. However, if you’re using GitHub Actions to automate your publishing process, setting up **Trusted Publisher** is a more secure option.
@@ -231,7 +202,7 @@ If you look at the pyometra workflow, notice that we have an [environment called
231202
url: https://pypi.org/p/pyosmeta
232203
```
233204
234-
## Sanitize a branch name in your workflow, before calling it!
205+
## 6. Sanitize a branch name in your workflow, before calling it!
235206
236207
One of the critical issues in the Ultralytics breach was that attackers crafted a [**malicious branch name containing a shell script**](https://github.com/ultralytics/ultralytics/pull/18020) 🤯. This script executed within the GitHub Action workflow because the branch name was directly referenced using `github.ref`.
237208

@@ -304,31 +275,22 @@ The good news here is that if you use a release-based workflow as discussed earl
304275

305276
Restricting publish workflows to tagged releases significantly reduces the risk of such attacks.
306277

307-
### Delete old tokens
308-
309-
If you are using a trusted publisher workflow but have previously created PyPI API tokens for your package to use in GitHub Actions, it’s time to clean house:
310-
311-
- Identify and revoke/delete any unused or old tokens in your PyPI account!!
312-
- Do the same for your GitHub secrets!
313-
- Migrate to Trusted Publisher workflows to avoid using tokens entirely (if you can).
314278

315279
## GitHub & PyPI security tips
316280

317-
The above tips are focused on your GitHub workflows. However, you can also consider locking down your accounts too!
318-
319-
* Make sure you have 2FA (2-factor authentication) setup for both PyPI and GitHub. This is common these days for financial and even social media accounts. Set things up for your tech and open source accounts too!
320-
321-
Important: Store recovery codes securely (e.g., a password manager).
322-
323-
* Be careful about who can gain direct write access to your project's repository. Only a specific, trusted subset of maintainers should be able to trigger a publish-to-PyPI workflow. Most contributors and maintainers don’t need direct write access to your repository; limiting access reduces security risks.
281+
In addition to securing your workflows, lock down your accounts and repositories:
324282

283+
- **Enable 2FA (2-factor authentication)** for both PyPI and GitHub to prevent unauthorized access. Store recovery codes securely (e.g., in a password manager).
284+
- **Revoke old tokens**: If you've previously created PyPI API tokens or GitHub secrets, delete any unused or outdated ones.
285+
- **Restrict repository access**: Limit write access to a trusted subset of maintainers. Most contributors don’t need direct write access, which reduces security risks.
325286

326287
## Learn More
327288

328289
pyOpenSci follows best practices for PyPI publishing using our custom GitHub Actions workflow. Check out our tutorial on Python packaging here:
329290
👉 [pyOpenSci Packaging Tutorial](https://www.pyopensci.org/python-package-guide/package-structure-code/python-package-structure.html)
330291
👉 Join our discourse here
331292

293+
<div class="notice" markdown="1">
332294
## Get involved with pyOpenSci
333295

334296
* Keep an eye on our [events page](/events.html) for upcoming training events.
@@ -342,3 +304,4 @@ Follow us on social platforms:
342304
* [<i class="fa-brands fa-github"></i> GitHub](https://github.com/pyOpenSci)
343305

344306
If you are on LinkedIn, you should [subscribe to our newsletter, too](https://www.linkedin.com/newsletters/7179551305344933888/?displayConfirmation=true).
307+
</div>

0 commit comments

Comments
 (0)