PyPI spellcheckpy Typosquatting RAT Campaign

Attackers published typosquatted versions of the popular pyspellchecker library to deliver a Remote Access Trojan (RAT) hidden inside compressed Basque dictionary files.

Date:
Severity:
critical
Sources:
4
#pypi#typosquatting#rat#malware

Executive Summary

In January 2026, security researchers at Aikido Security discovered an evasive software supply chain attack campaign on the Python Package Index (PyPI) Aikido Security. Threat actors published two typosquatted packages, spellcheckerpy and spellcheckpy, designed to impersonate the highly popular and widely utilized spelling correction library pyspellchecker Aikido Security.

To bypass automated registry security sandboxes and static code analysis tools, the attackers hid a base64-encoded, zlib-compressed Python Remote Access Trojan (RAT) downloader inside a benign Basque language frequency dictionary resource file (resources/eu.json.gz) Aikido Security. In early iterations, the malware remained dormant to establish registry trust, but with the release of spellcheckpy version 1.2.0 on January 21, 2026, the threat actors enabled an import-time execution trigger inside the class constructor Aikido Security.

Once executed, the downloader establishes persistence, bypasses SSL verification, and beacons every 5 seconds to a malicious command-and-control (C2) server hosted on known bulletproof C2 infrastructure Aikido Security Halcyon. Security teams should immediately hunt for and remove references to these packages and treat any exposed environments as fully compromised.


Key Facts

threat_type: typosquatting, malicious package, Remote Access Trojan (RAT), credential theft
ecosystem: pypi
registry: PyPI
affected_packages:
  - "spellcheckerpy"
  - "spellcheckpy"
malicious_versions:
  - "spellcheckerpy@*"
  - "spellcheckpy@1.2.0"
fixed_versions:
  - "none"
safe_versions:
  - "none (use pyspellchecker)"
exposure_window: 2026-01-20 to 2026-01-22
execution_trigger: Import-time execution (`WordFrequency.__init__`)
primary_impact: Remote Access Trojan (RAT) execution, credential theft, remote system access, files harvesting
known_iocs:
  - "updatenet[.]work"
  - "172.86.73[.]139"
  - "https://updatenet[.]work/update1.php"
  - "https://updatenet[.]work/settings/history.php"
  - "dothebest[.]store"
  - "FD429DEABE"
  - "resources/eu.json.gz"
confidence: high
canonical_source: https://www.aikido.dev/blog/malicious-pypi-packages-spellcheckpy-and-spellcheckerpy-deliver-python-rat

Source Confidence & Evidence Mapping

  • confirmed:
    • The discovery of malicious spellcheckpy and spellcheckerpy packages on PyPI that typosquatted pyspellchecker Aikido Security.
    • The payload evasion method of embedding zlib-compressed, base64-encoded Python scripts under the "spellchecker" key inside Basque dictionary files (resources/eu.json.gz) Aikido Security.
    • The import-time trigger added to spellcheckpy version 1.2.0 on January 21, 2026, within the WordFrequency.__init__ class constructor Aikido Security.
    • The active beaconing to C2 domain updatenet[.]work at IP 172.86.73[.]139 using HTTPS POST requests Aikido Security.
    • An identical campaign discovered in November 2025 by HelixGuard under the package name spellcheckers communicating with C2 domain dothebest[.]store HelixGuard.
  • likely:
    • Threat actors targeted software developers working with spelling or linguistic modules to steal operational credentials (such as AWS keys, GitHub tokens, database logins) or cryptocurrency keys Aikido Security HelixGuard.
    • The use of RouterHosting LLC (Cloudzy) as a bulletproof host chosen specifically for its low-verification signup policies and cryptocurrency payment options Halcyon.
  • unclear:
    • The exact geographic location or definitive group attribution of the threat actors, though the C2 infrastructure utilized is heavily correlated with Iranian and Russian threat actors Halcyon.
    • The complete list of downstream victims, other than the registry-tracked download counts indicating approximately 1,000 installations Aikido Security.
  • not_observed:
    • Any self-propagating worm capabilities; the malware relies purely on targeted installation via typosquatting Aikido Security.
    • Exploitation of software bugs or zero-day vulnerabilities; this attack is a social engineering-centric registry supply chain injection Aikido Security.

Timeline

  • 2025-10-28T00:00:00Z The malicious C2 domain updatenet[.]work is registered. Source: Aikido Security
  • 2025-11-19T00:00:00Z HelixGuard documents a functionally identical campaign involving the typosquatted package spellcheckers communicating with C2 domain dothebest[.]store. Source: HelixGuard
  • 2026-01-20T00:00:00Z Aikido Security’s automated malware detection pipeline identifies initial dormant uploads of spellcheckerpy and spellcheckpy on PyPI. Source: Aikido Security
  • 2026-01-21T00:00:00Z The threat actor publishes version 1.2.0 of spellcheckpy, switching the malware from dormant to active by embedding an execution trigger in the class constructor. Source: Aikido Security
  • 2026-01-22T00:00:00Z The packages are reported to PyPI security and removed from the registry after reaching approximately 1,000 downloads. Source: Aikido Security
  • 2026-01-23T00:00:00Z Aikido Security publishes a detailed threat analysis detailing the RAT extraction and payload behavior. Source: Aikido Security

What Happened

In late January 2026, security analysts at Aikido Security flagged suspicious activity involving spelling correction libraries on PyPI Aikido Security. A threat actor had uploaded two packages—spellcheckerpy and spellcheckpy—which typosquatted the popular and legitimate pyspellchecker library Aikido Security.

To bypass standard registry scanning mechanisms that flag classic indicators like shell commands (subprocess.run(), eval(), exec()) in setup files, the attackers utilized a multi-stage, evasive deployment model Aikido Security. They first uploaded several “dormant” versions containing the obfuscated downloader code inside a Basque language frequency dictionary, but without active calls to execute it Aikido Security.

On January 21, 2026, the attackers published version 1.2.0 of spellcheckpy Aikido Security. This version modified the initialization routine of the WordFrequency class to compile and execute the base64-decoded dictionary data upon import Aikido Security. Consequently, any developer importing the library unwittingly triggered the download and execution of a fully featured Remote Access Trojan (RAT) Aikido Security.

The package was reported to PyPI administrators and removed on January 22, 2026, limiting the blast radius to roughly 1,000 installations Aikido Security. Subsequent research linked the campaign to a functionally identical incident documented by HelixGuard in November 2025 Aikido Security HelixGuard.


Technical Analysis

Initial Access

The primary entry point is typosquatting Aikido Security. The attackers relied on developers typing the wrong library name (spellcheckpy or spellcheckerpy instead of pyspellchecker) during local installation or manually writing their dependency files Aikido Security.

Package or Artifact Manipulation

The packages were structured similarly to the legitimate pyspellchecker project, mimicking standard linguistic modules Aikido Security. However, the file resources/eu.json.gz, which is legitimately used to store compressed Basque language word frequencies, was weaponized Aikido Security. The attackers injected a key named "spellchecker" containing a base64-encoded, compressed Python payload representing the first-stage downloader Aikido Security.

In early “dormant” releases, the loader file utils.py contained code to read the file but omitted execution routines, rendering it invisible to security monitors Aikido Security:

def test_file(filepath: PathOrStr, encoding: str, index: str):
    # Reads compressed data but does not trigger execution

Execution Trigger

The execution trigger was flipped in version 1.2.0 of spellcheckpy Aikido Security. The threat actor modified the constructor function WordFrequency.__init__ Aikido Security. When a developer imports the module and instantiates the spelling checker, the system runs the constructor, which immediately compiles and executes the hidden script Aikido Security:

if eval(compile(base64.b64decode(test_file("eu", "utf-8", "spellchecker")).decode("utf-8"), ...)):
    exec(szCode)

Payload Behavior

Once compiled and executed, the downloader performs the following sequences Aikido Security:

  1. SSL Disabling: It disables local SSL verification using ssl._create_unverified_context() to ensure smooth connection routing Aikido Security.
  2. Beaconing Loop: It establishes a persistent beaconing loop, executing an HTTPS POST request every 5 seconds to https://updatenet[.]work/update1.php Aikido Security.
  3. Telemetry Exfiltration: The POST payload carries a unique victim machine identifier, system metrics, and a hardcoded Campaign ID (FD429DEABE) Aikido Security.
  4. Encrypted Command Execution: The C2 server responds with encrypted commands, which the client decrypts using a 16-byte XOR key array (03 06 02 01 06 00 04 07 00 01 09 06 08 01 02 05) and a secondary XOR key (0x7B) Aikido Security. The RAT supports full remote shell access, command execution, local file harvesting, and targeted credential theft Aikido Security.

Exfiltration / C2

domains:
  - "updatenet[.]work"
ips:
  - "172.86.73[.]139"
urls:
  - "https://updatenet[.]work/update1.php"
  - "https://updatenet[.]work/settings/history.php"
protocols:
  - "HTTPS"
endpoints:
  - "/update1.php"
  - "/settings/history.php"
confidence: high

Propagation

The malicious code does not contain lateral propagation or worm-like replication capabilities Aikido Security. It relies entirely on developers manually importing the typosquatted package or pulling it via misconfigured automated dependency requirements Aikido Security.

Obfuscation or Evasion

  • Steganographic Data Blending: Embedding base64-encoded, zlib-compressed payloads inside Basque frequency dictionary resource files which are structurally standard in spelling utilities Aikido Security.
  • Dormant Upload Staging: Releasing multiple early versions of the package with the downloader code but no execution trigger, avoiding automated publish-time detection systems Aikido Security.
  • Dynamic Code Compilation: Avoiding obvious dynamic evaluation keywords like exec() or eval() directly in the primary package script and compiling strings dynamically inside standard class constructors (WordFrequency.__init__) Aikido Security.

Affected Assets and Blast Radius

affected_assets:
  ecosystems:
    - pypi
  packages:
    - spellcheckerpy
    - spellcheckpy
  versions:
    - spellcheckerpy (all versions)
    - spellcheckpy (all versions, trigger active in 1.2.0)
  repositories: []
  container_images: []
  CI_CD_systems: []
  developer_tools: []
  environments:
    - developer workstations
    - CI runners
    - build pipelines
    - containers
    - production systems

credentials_at_risk:
  - environment variables
  - SSH keys
  - cloud provider credentials
  - database connection keys
  - API tokens
  - cryptocurrency wallet keys

not_currently_known_to_affect:
  - legitimate pyspellchecker users
  - systems where spellcheckerpy or spellcheckpy was installed but the SpellChecker or WordFrequency class was never instantiated or imported (for versions < 1.2.0)

Indicators of Compromise

Domains

IPs

URLs

Files

Package Versions


Detection and Hunting

hunt_queries:
  dependency_lockfiles:
    - "spellcheckpy"
    - "spellcheckerpy"
  files:
    - "resources/eu.json.gz"
  network:
    - "updatenet.work"
    - "dothebest.store"
    - "172.86.73.139"
  ci_cd_checks:
    - "Search all poetry.lock, Pipfile, requirements.txt, and setup.py files for references to 'spellcheckpy' or 'spellcheckerpy'."
  endpoint_checks:
    - "Inspect system sockets and process tables for active python network processes communicating with 172.86.73.139."
    - "Search Python installation directories for 'resources/eu.json.gz' containing base64-encoded loaders with the dictionary key 'spellchecker'."

Remediation Workflow

  • Immediate:
    1. Execute pip uninstall spellcheckpy spellcheckerpy and purge local caches with pip cache purge to prevent cache-based reinstallations.
    2. Identify and immediately terminate all active Python processes that imported the compromised libraries.
    3. Configure network perimeter firewalls and local DNS proxies to block all outgoing traffic to updatenet[.]work, dothebest[.]store, and IP 172.86.73[.]139.
    4. Revoke all environment variables, SSH keys, cloud provider access tokens, and database logins present on any host where the active versions were run.
  • Short-term:
    1. Inspect host file access records and security event logs to verify whether any local data files or secrets directories were accessed by Python processes.
    2. Verify integrity of local developer environments and check cryptocurrency wallet logs for anomalous outbound transactions.
  • Long-term:
    1. Enforce the use of strict dependency lockfiles with SHA-256 integrity hash verification (e.g., via poetry or pip-compile).
    2. Establish internal private package mirrors or repository proxies (such as Nexus or Artifactory) configured with allowlists to prevent accidental typosquatted dependency pulling.
    3. Enforce network egress filtering on build-runners and production containers, blocking arbitrary outbound internet connections.

Defensive Lessons

  • prevent: Always double-check package names against official project pages or use dependency verification systems that validate hashes to prevent developers from installing typosquatted clones.
  • detect: Maintain persistent logging and behavioral analysis of outbound network connections originating from containerized workloads and CI/CD pipelines to catch unrecognized RAT beaconing.
  • respond: Deploy automated incident response systems that can quickly revoke developer session tokens and rotate cloud credentials the moment a supply chain threat indicator is matched.

Open Questions

  • The total number of private production environments that installed and ran version 1.2.0 before it was officially taken down.
  • The potential existence of other language dictionaries (e.g. fr.json.gz or de.json.gz) in similar projects that could be hiding comparable dormant loaders.
  • The exact criminal group behind the infrastructure registration, although C2 infrastructure points heavily to Cloudzy network utilization.

Sources

  1. Aikido Security. Role: PRIMARY_RESEARCH Impact: Detailed the discovery of the spellcheckpy typosquatting campaign, payload extraction, and import-time execution trigger in version 1.2.0.
  2. HelixGuard. Role: PRIMARY_RESEARCH Impact: Documented the November 2025 typosquatted campaign under the package name spellcheckers communicating with C2 domain dothebest[.]store using an identical codebase.
  3. Halcyon. Role: ENRICHMENT_DATA Impact: Published the “Cloudzy with a Chance of Ransomware” investigation exposing RouterHosting LLC (Cloudzy) as an Iranian-linked C2P provider heavily utilized by APTs and ransomware groups.
  4. The Hacker News. Role: SECONDARY_ANALYSIS Impact: Aggregated reporting of the typosquatted package takedown timeline on PyPI.