Detecting and Analyzing a PyPI Supply Chain Attack: The ZiChatBot Case Study
Overview
In July 2025, a sophisticated supply chain attack targeting the Python Package Index (PyPI) was uncovered. Threat actors linked to the OceanLotus group uploaded malicious wheel packages disguised as legitimate libraries. These packages, while appearing to perform benign functions, secretly delivered a previously unknown malware family named ZiChatBot. Unlike traditional botnets, ZiChatBot does not rely on a dedicated command-and-control (C2) server; instead, it abuses the public REST APIs of the Zulip team chat application to receive commands and exfiltrate data. This case study walks through the detection, analysis, and understanding of this attack, providing a practical guide for security researchers and defenders.

The attack involved three fake PyPI projects: uuid32-utils, colorinal, and termncolor. These packages were designed to mimic popular libraries, tricking developers into installing them via pip install. Once installed, the malicious packages dropped either a DLL (Windows) or shared object (.so) file (Linux), serving as a dropper for the final ZiChatBot payload. The campaign highlights the importance of monitoring open-source package repositories for malicious activity.
Prerequisites
Knowledge Requirements
- Basic understanding of Python package management and PyPI.
- Familiarity with malware analysis concepts (e.g., droppers, DLL injection, C2 communication).
- Experience with static and dynamic analysis tools (e.g., IDA Pro, Ghidra, Wireshark).
Tools and Environment
- A sandboxed analysis environment (e.g., VirtualBox with Windows and Linux VMs).
- Python 3.x installed for examining wheel packages.
- Network analysis tools (e.g., mitmproxy, Wireshark) to capture API calls.
- Threat intelligence platforms (e.g., Kaspersky Threat Attribution Engine) for cluster analysis.
Step-by-Step Guide
1. Identifying Malicious PyPI Packages
The first step is to recognize suspect packages in the PyPI repository. In this case, the attacker uploaded three packages with recent first-upload dates and suspicious author emails:
- uuid32-utils (laz**** / laz****@tutamail.com) – uploaded July 16, 2025.
- colorinal (sym**** / sym****@proton.me) – uploaded July 22, 2025.
- termncolor (sym**** / sym****@proton.me) – uploaded July 22, 2025.
These packages claim to provide UUID generation and terminal color formatting, but they contain hidden malicious code. To identify such threats, examine the wheel file metadata and check for unexpected .pyd or .so files. For example, the colorinal project offers multiple platform-specific wheels:
- Windows X86 and X64
- Linux x86_64
Download and extract a wheel file using unzip to inspect its contents. Look for binary files in unexpected locations (e.g., inside colorinal/ directory alongside Python scripts). The presence of a DLL or .so file that isn't part of a standard Python extension may indicate a dropper.
2. Analyzing the Infection Chain
Both uuid32-utils and colorinal use similar infection chains. The focus here is on colorinal. After installation, the package imports a module that loads the malicious binary from a hardcoded location. For example, the code might do:
import os
import sys
# Decode and execute shellcode or load DLL
if sys.platform == 'win32':
os.system('rundll32.exe malicious.dll') # simplified example
In reality, the actual loading mechanism is obfuscated. The dropper decrypts or extracts the payload (ZiChatBot) and runs it in memory to avoid disk detection. On Linux, it uses dlopen to load a shared library. The payload communicates back to the attacker via the Zulip API.
To analyze the dropper statically, decompile the Python bytecode using tools like uncompyle6 or pycdc. Look for strings referencing Zulip endpoints, API keys, or encryption routines.
3. Understanding the ZiChatBot Payload
ZiChatBot is a new malware family that, instead of traditional C2, uses the Zulip team chat service's public REST API. The bot registers as a Zulip user (or abuses an existing bot account) to listen for commands and send back data. Key characteristics:

- Cross-platform: Windows DLL and Linux .so versions exist.
- No hardcoded IPs: All communication goes through api.zulip.com, making network detection harder.
- Command structure: The bot subscribes to a specific stream/topic; commands are posted as messages. Example commands: execute shell, upload file, list directory.
Reverse-engineer the binary (e.g., using IDA Pro for the DLL) to identify the Zulip API calls, like GET /messages or POST /messages. The bot likely uses an API token stored encrypted within the dropper.
4. Mapping C2 via Zulip APIs
To understand the command flow, set up a test environment and run the malware (in a sandbox) with network monitoring. Use mitmproxy or Wireshark to capture HTTPS traffic to Zulip API endpoints. Look for patterns:
/api/v1/messageswith parametersstream=...andtopic=...- Base64-encoded payloads in message bodies.
- Polling intervals (e.g., every 30 seconds).
By analyzing the traffic, you can understand the bot's update cycle and potentially spoof the C2 to issue decoy commands. The attacker creates a dedicated Zulip organization and stream for each victim group, making it harder to take down.
Common Mistakes and Pitfalls
- Assuming PyPI packages are safe: Always verify the author, recent uploads, and download history before installing.
- Ignoring platform-specific wheels: Attackers often target both OS families; a
.whlwith multiple platform suffixes should raise suspicion. - Overlooking dependencies: The attacker created a benign package that depended on the malicious one. Always review transitive dependencies.
- Misidentifying C2: Because ZiChatBot uses a legitimate SaaS, network teams might allow traffic to Zulip APIs, missing the malicious behavior.
- Static analysis only: Without dynamic execution, you might miss encrypted payloads. Use both static and dynamic methods.
Summary
This case study reveals how the OceanLotus group executed a PyPI supply chain attack using three fake packages to deliver the ZiChatBot malware. By imitating common libraries (UUID generation, color formatting) and leveraging Zulip's REST APIs for C2, the attackers evaded traditional detection. Defenders must adopt proactive measures: scrutinizing package metadata, analyzing wheel contents, monitoring for unusual network traffic to SaaS APIs, and sharing threat intelligence. The ZiChatBot campaign underscores the evolving sophistication of supply chain threats and the need for continuous vigilance in open-source ecosystems.