Skip to content

uv's Malware Check: What It Blocks and What It Misses

July 22, 2026·Tim Hopper · Markdown

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 = true

Everyone 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.dev or a mirror you host via malware-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 install and uv tool install don’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

Last updated on