The Ultralytics PyPI Supply Chain Attack
Updated 5 Oct 2026 · Incident date 4 Dec 2024 · PyPI
ultralytics 8.3.40 -> 8.3.41, 8.3.42 (and again 8.3.45, 8.3.46)ultralytics/models/yolo/model.pyThe PyPI package ultralytics versions 8.3.41, 8.3.42, 8.3.45 and 8.3.46 installed a cryptocurrency miner. Version 8.3.40 was the last clean release before the attack in December 2024.
The first two versions came from a poisoned GitHub Actions workflow. The last two came from a stolen PyPI API token.
What happened
On 4 December 2024 an attacker abused the Ultralytics GitHub Actions publishing workflow. Socket reports that researcher Adnan Khan found the payload was delivered by GitHub Actions cache poisoning, using template injection in custom actions. HiddenLayer adds that the attack used branch names that carried malicious commands.
Socket gives this timeline in UTC:
- 4 December 20:51: version 8.3.41 released
- 5 December 09:15: 8.3.41 removed, after about 12 hours
- 5 December 12:47: 8.3.42 released
- 5 December 13:47: 8.3.42 removed, after about one hour
- Later: 8.3.45 and 8.3.46 released and removed
Socket says the last two versions used an API token from the maintainer's account. Ultralytics had not deleted the old tokens when it registered a Trusted Publisher.
HiddenLayer describes the code changes. In 8.3.41 and 8.3.42, the files models/yolo/model.py and utils/downloads.py changed. The code detected the operating system and architecture, downloaded an XMRig miner and ran it through a new safe_run() function to mine Monero. Version 8.3.45 added code in __init__.py that sent environment variables and directory listings to a webhook service. Version 8.3.46 targeted Linux and downloaded XMRig 6.22.2 with wget.
Affected versions
Four releases of ultralytics on PyPI are affected.
- 8.3.41 and 8.3.42: cache poisoning attack, miner download
- 8.3.45 and 8.3.46: stolen API token, miner download and data exfiltration
Version 8.3.40 was clean. Version 8.3.43 and 8.3.44 are not named in the sources I fetched. Socket and HiddenLayer both say the code on GitHub did not match what PyPI served.
Indicators of compromise
HiddenLayer lists these indicators.
- Binary path:
/tmp/ultralytics_runner - Mining pool domain:
connect.consrensys.com - Exfiltration webhooks on
webhook.site(one for Linux, one for macOS) - SHA-256 of the 8.3.41 wheel:
b6ea1681855ec2f73c643ea2acfcf7ae084a9648f888d4bd1e3e119ec15c3495 - SHA-256 of the XMRig binary:
b0e1ae6d73d656b203514f498b59cbcf29f067edf6fbd3803a3de7d21960848d - Sudden 100 percent CPU use after an update to 8.3.41
HiddenLayer reports that the webhooks received requests from Docker containers, Google Colab, GitHub Actions and AWS SageMaker.
How to check
Check the installed version.
pip show ultralytics
Version 8.3.41, 8.3.42, 8.3.45 or 8.3.46 means you were affected. Then look for the miner binary and process.
ls -l /tmp/ultralytics_runner; pgrep -fl ultralytics_runner
Search your lockfiles and image build logs for the bad versions.
grep -rnE "ultralytics(==|=| )8\.3\.(41|42|45|46)" . --include=requirements*.txt --include=*.lock --include=*.toml
What to do now
- Uninstall the affected version and install a clean release.
- Stop the
ultralytics_runnerprocess and delete/tmp/ultralytics_runner. - Run a full antivirus scan.
- Rotate any token or key that was in the environment of the machine, especially for 8.3.45 and 8.3.46, which sent environment variables out.
- Check cloud bills for unexpected compute use.
- If you publish packages, remove old API tokens when you move to Trusted Publishing, and keep publishing in a dedicated workflow with scoped permissions.
Vigilance compares the version you trust with a new one and reports the file that gained a new capability. Here model.py gained download-and-run behavior. See all attacks.
What Vigilance showed
Vigilance compares the version you trust with the new one and names the file that gained a new capability. The block below is rebuilt from the public reports in the words Vigilance prints. It is not a captured scan, because the malicious release is not redistributed.
files scanned: 45 (1 Added) HEADS UP 1 file can now do things the old version could not. The rest changed and gained nothing. NEW FILE ultralytics/models/yolo/model.py It downloads from the internet and runs other programs.
Frequently asked questions
Which ultralytics versions were compromised?
Versions 8.3.41, 8.3.42, 8.3.45 and 8.3.46 on PyPI installed a cryptocurrency miner. Version 8.3.40 was clean.
How was Ultralytics compromised?
The first two versions came from GitHub Actions cache poisoning in the publishing workflow. The last two came from a stolen PyPI API token.
Sources
More supply chain attacks
- Microsoft durabletask PyPI compromise (TeamPCP) 19 May 2026
- LiteLLM PyPI backdoor (TeamPCP) 24 Mar 2026
- num2words hijack (PyPI phishing campaign / Scavenger malware) 28 Jul 2025
- aiocpa crypto-pay library poisoned release 20 Nov 2024
All 111 attacks in the library · What is a supply chain attack? · How to prevent supply chain attacks
Check the next update before you install it
Vigilance compares the version you trust with the new one. It names the one file that can now do something it could not do before.