uv's Malware Check: What It Blocks and What It Misses
When litellm was compromised in March, the malicious versions sat on PyPI for hours. When lightning was hit in April, Socket flagged the bad releases 18 minutes after upload. Any uv sync inside those windows installed the malware. uv has a defense for the tail end of these incidents: an install-time check that refuses to install any package version with a published malware advisory. As of uv 0.11.31, you can turn it on in pyproject.toml instead of hoping every developer remembers an environment variable.
Turn it on for the whole project
Add two lines to pyproject.toml:
[tool.uv.audit]
malware-check = trueEveryone who clones the project and runs uv sync now gets the check, including CI. The UV_MALWARE_CHECK=1 environment variable (available since 0.11.16) still works for one-off sessions or pipelines where you’d rather not touch project config.
What does the check do?
On every command that syncs the environment (uv add, uv sync, and others), uv looks up the locked packages against the MAL advisories in the OSV database, sourced from the OpenSSF malicious-packages project. If a locked version matches an advisory, uv stops the sync before the package lands in your environment. The litellm payload ran at interpreter startup; the lightning payload ran on import. A package that never gets installed does neither.
The lookup is cheap: on a small project, sync output reports Checked 1 package in 0.39ms.
Organizations with their own advisory feed can point malware-check-url at an internal endpoint instead of the default api.osv.dev.
Where does it fall short?
- It only blocks known malware. The check matches published advisories, and advisories lag uploads. Socket’s scanner caught the lightning compromise in 18 minutes, but an advisory must be filed and propagated to OSV before uv can act. A sync inside that gap passes the check. A dependency cooldown covers the gap:
exclude-newer = "7 days"keeps brand-new versions out until the ecosystem has vetted them. - It needs the network. Each sync queries the advisory service, so the check assumes access to
api.osv.devor a mirror you host viamalware-check-url. Air-gapped builds don’t get it for free. - It only covers project syncs. The check inspects packages in the project’s lockfile. Installs through
uv pip installanduv tool installdon’t go through that path. - It’s a preview feature. Sync output warns that malware checks “may change without warning,” and the config settings shipped hours ago. Expect the interface to move before it stabilizes.
None of these are reasons to skip it. The check costs milliseconds and blocks the exact attack that hit litellm and lightning users. Enable it, then add a cooldown for the advisory gap, and you’ve covered both halves of the timeline. The supply chain how-to walks through the full setup.
Learn more
- How to Protect Against Python Supply Chain Attacks with uv
- How to Scan Python Dependencies for Vulnerabilities covers
uv audit, the after-the-fact companion to the install-time check. - Vulnerability and malware checks in uv is Astral’s announcement of the feature.
- uv audit settings reference