The num2words PyPI Supply Chain Attack

Updated 5 Oct 2026 · Incident date 28 Jul 2025 · PyPI

Packagenum2words 0.5.14 -> 0.5.15 and 0.5.16
Filenum2words/__init__.py

The PyPI package num2words versions 0.5.15 and 0.5.16 contained malware. Version 0.5.14 was clean. An attacker phished the maintainer's PyPI credentials and uploaded the bad releases on 28 July 2025.

The code ran when the package was imported on Windows. It loaded a native DLL named Scavenger that stole files and credentials.

What happened

A phishing email reached the package owner. It pointed to a fake PyPI site at pypj.org, which used a lowercase j in place of the i. The PyPI incident report says four accounts were phished and two API tokens were created, then revoked. The attacker used the stolen credentials to upload malware to PyPI.

PyPI reports that the owner removed the bad versions and that the advisory is PYSEC-2025-72. The registrar NameSilo placed the phishing domain on administrative hold on 28 July.

According to the Invoke RE analysis, the bad __init__.py checks whether the system is Windows. If it is, the code loads a file named _build.py, which is a DLL, and calls its main export through ctypes. The DLL is the Scavenger loader. Invoke RE reports a build time of 28 July 2025, 07:22 UTC.

The loader can fetch stealer modules. Invoke RE names three:

The malware also goes after .pypirc files, which hold PyPI credentials, plus wallet files and browser and system credentials.

Affected versions

Versions 0.5.15 and 0.5.16 of num2words are affected. Version 0.5.14 was the last clean release before the incident.

The loader code runs only on Windows. Linux and macOS systems that installed these versions still received the bad package files.

Indicators of compromise

Invoke RE publishes the full list in its IOC file. These are the main items.

How to check

Check the installed version first. Any result of 0.5.15 or 0.5.16 means you must act.

pip show num2words

Then look for the loader file in the package folder. This lists it if present. The command does not import the package.

pip show -f num2words | grep -i _build

Also search your lockfiles and build caches for the bad versions.

grep -rn "num2words==0.5.1[56]" . --include=requirements*.txt --include=*.lock

What to do now

  1. Uninstall the bad version and install a clean one, such as 0.5.14 or a later release you have checked.
  2. If a bad version was imported on Windows, treat the machine as compromised.
  3. Rotate credentials in any .pypirc file, plus browser and system credentials stored on the machine.
  4. Move cryptocurrency wallet funds if wallet software was present.
  5. Block the command domains in the IOC list.
  6. If you publish on PyPI, enable WebAuthn two-factor sign-in with a hardware key, and delete dormant accounts. PyPI recommends both.

Vigilance compares the version you trust with a new one and reports the file that gained a new capability. Here __init__.py gained code that loads and runs a native DLL. 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.

vigi diff --old num2words-0.5.14 --new num2words-0.5.15
files scanned: 54

HEADS UP  1 file can now do things the old version could not. The rest changed and gained nothing.

CHANGED    num2words/__init__.py
           It now runs other programs. It did not before.

Frequently asked questions

Which num2words versions are malicious?

Versions 0.5.15 and 0.5.16 contained the Scavenger loader. Version 0.5.14 was clean.

How was num2words compromised?

An attacker phished the maintainer's PyPI credentials with a fake site at pypj.org and used them to upload malicious releases on 28 July 2025.

Sources

  1. blog.pypi.org/posts/2025-07-31-incident-report-phishing-attack/
  2. invokere.com/posts/2025/07/scavenger-malware-distributed-via-num2words-pypi-supply-chain-compromise/
  3. github.com/Invoke-RE/community-malware-research/blob/main/Research/Loaders/Scavenger/num2words_IOCs.md

More supply chain attacks

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.

Start Free