PyPI Packages Deliver ZiChatBot Malware via Zulip APIs on Windows and Linux
Cybersecurity researchers have discovered three packages on the Python Package Index (PyPI) repository that are designed to stealthily deliver a previously unknown malware family called ZiChatBot on Windows and Linux systems. "While these wheel packages do implement the features described on their PyPI web pages, their true purpose is to covertly deliver malicious files," Kaspersky said in a report.
The Poisoned Packages
The malicious packages, which have since been taken down, are:
- uuid32-utils (1,479 downloads) - colorinal (614 downloads) - termncolor (387 downloads)
All three packages were uploaded to PyPI during a short window between July 16 and 22, 2025. While uuid32-utils and colorinal make use of similar malicious payloads, termncolor is a benign-looking package that lists colorinal as a dependency—creating a supply chain infection that spreads through legitimate dependency resolution.
The Infection Chain
Windows Infection
On Windows systems, once any of the first two packages is installed, the malicious code:
- Extracts a DLL dropper (terminate.dll) and writes it to disk - When the library is imported into a project, the DLL is loaded - The DLL acts as a dropper for ZiChatBot - Establishes an auto-run entry in the Windows Registry - Runs code to delete itself from the host (covering its tracks) Linux Infection
The Linux version of the shared object dropper (terminate.so) plants the malware in the /tmp/obsHub/obs-check-update path and configures a crontab entry for persistence.
Regardless of the operating system, ZiChatBot is designed to execute shellcode received from its C2 server. After executing the command, the malware sends a heart emoji ❤️ as a response to signal the server that the operation was successful.
The C2 Innovation: Zulip APIs
Unlike traditional malware, ZiChatBot does not communicate with a dedicated command-and-control (C2) server. Instead, it uses a series of REST APIs from the public team chat app Zulip as its C2 infrastructure.
This approach offers several advantages:
- Legitimate traffic: Zulip API calls blend with normal business communication - Hard to block: Blocking Zulip would disrupt legitimate users - Resilient: No dedicated C2 infrastructure to take down - Encrypted: Zulip uses TLS, making inspection difficult - Free infrastructure: Attackers don't pay for C2 hosting
The use of collaboration platforms as C2 is a growing trend. We've seen Telegram, Discord, Slack, and now Zulip weaponized for this purpose. It's a defender's nightmare: how do you block malicious traffic when it's indistinguishable from legitimate business communication?
Attribution: OceanLotus Connection?
Exactly who is behind the campaign is not clear. However, Kaspersky said the dropper shares a 64% similarity to another dropper used by a Vietnam-aligned hacking group named OceanLotus (aka APT32).
In late 2024, OceanLotus was observed targeting the Chinese cybersecurity community with poisoned Visual Studio Code projects masquerading as Cobalt Strike plugins to deliver a trojan that executed automatically when the project was compiled. That malware used the Notion note-taking service as C2.
If the PyPI supply chain campaign is indeed the work of OceanLotus, it represents the threat actor's strategy to expand its targeting scope. "Although phishing emails are still a common initial infection method for OceanLotus, the group is also actively exploring new ways to compromise victims through diverse supply chain attacks," Kaspersky noted.
Reflection: The PyPI Trust Problem
1. The Supply Chain Dilemma
PyPI is a cornerstone of modern Python development. Developers rely on it for:
- Code reuse: Why write a UUID library when uuid32-utils exists? - Time savings: Install a package in seconds, save hours of development - Community trust: Popular packages are assumed to be safe
But this trust is weaponized. Attackers don't need to hack your systems—they just need to upload a malicious package and wait for developers to install it.
2. The "Works as Advertised" Trick
ZiChatBot's packages actually work. uuid32-utils generates UUIDs. colorinal handles color output. This isn't lazy malware—it's dual-use software that performs its stated function and infects your system.
This makes detection exponentially harder:
- Static analysis: The code does what it claims to do - Functional testing: The package works correctly - User experience: No obvious signs of compromise
The malicious payload is a side effect, not the primary function. This is supply chain attack sophistication at its finest.
3. The Emoji C2 Signature
ZiChatBot sends a heart emoji ❤️ to confirm successful command execution. This is both clever and chilling:
Clever because:
- It's a valid Zulip message (not suspicious) - Short and efficient (minimal data transfer) - Easy to parse (the C2 operator knows ❤️ = success)
Chilling because:
- It's a playful, human touch in a malicious operation - It shows the attackers are confident, almost casual - It's a signature—potentially linkable to other campaigns 4. The Download Numbers Don't Lie
Combined, these three packages were downloaded 2,480 times. Each download represents a potentially compromised system. But the real number is likely higher:
- CI/CD pipelines: Automated builds may have installed the packages - Production deployments: Compromised packages may be running in production - Transitive dependencies: termncolor depended on colorinal, spreading the infection further
For each of these 2,480 downloads, someone needs to answer:
- Was this package installed in production? - Does our codebase still depend on it? - Have we rotated credentials that may have been stolen? - Is our system still communicating with Zulip C2? 5. The OceanLotus Evolution
If this is OceanLotus, the group is evolving:
- 2024: Poisoned VS Code projects, Notion C2 - 2025: Poisoned PyPI packages, Zulip C2
The pattern: target developer tooling, use legitimate SaaS platforms for C2, and expand from narrow targets (Chinese security researchers) to broad targets (anyone using PyPI).
This is a democratization of compromise—casting a wider net to catch more victims.
Lessons for Development Teams
1. Audit Your Dependencies
Run pip list and pip show on all your projects. Check for:
- uuid32-utils, colorinal, termncolor (remove immediately if found) - Unfamiliar packages or packages with low download counts - Packages from unknown authors - Dependencies that seem unnecessary for your use case 2. Pin Your Versions
Never use floating versions in production (package>=1.0). Always pin exact versions (package==1.0.3). This prevents automatic updates from pulling in compromised versions.
3. Monitor for Zulip Traffic
If your systems don't legitimately use Zulip, monitor for connections to Zulip APIs. Unexpected Zulip traffic is a strong indicator of ZiChatBot infection.
4. Use Private Package Repositories
For production systems, consider using a private PyPI mirror (like DevPI or Artifactory) where you can:
- Curate approved packages - Scan packages for malware before allowing installation - Control which versions are available - Audit all package downloads 5. Implement Least Privilege
Python processes shouldn't run as root. Limit what your applications can do:
- No registry modification rights - No crontab access - Restricted network access (can't call arbitrary APIs) - Sandboxed execution environments (containers, VMs)
Conclusion
ZiChatBot represents the industrialization of supply chain attacks. It's not targeted—it's opportunistic at scale. The attackers poisoned the well and waited for developers to drink.
For the 2,480 developers who downloaded these packages, the question isn't if they're compromised—it's what the attacker has done with their access. And for the rest of us, it's a reminder: every pip install is an act of trust. Make sure that trust is warranted.
In the age of supply chain warfare, your dependencies are your attack surface. Audit them, pin them, and never assume safety.













