{
	"id": "273b3a2d-111b-4bf1-9739-9aecc3b96ee0",
	"created_at": "2026-04-06T00:15:23.139302Z",
	"updated_at": "2026-04-10T13:12:05.365347Z",
	"deleted_at": null,
	"sha1_hash": "99682021e4711f7e1b8404a27bb34fdc11b3a742",
	"title": "A Beautiful Factory for Malicious Packages",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2209775,
	"plain_text": "A Beautiful Factory for Malicious Packages\r\nArchived: 2026-04-05 17:58:54 UTC\r\nCheckmarx Supply Chain Security (SCS) team has uncovered hundreds of malicious packages attempting to use a\r\ndependency confusion attack. Customarily, attackers use an anonymous disposable NPM account from which they\r\nlaunch their attacks. As it seems this time, the attacker has fully-automated the process of NPM account creation\r\nand has open dedicated accounts, one per package, making his new malicious packages batch harder to spot.\r\nAt the time of writing, the threat actors RED-LILI is still active at the time of writing and continues to publish\r\nmalicious packages. So far, the packages listed in this report were detected by Checkmarx’s internal systems and\r\ndisclosed to NPM.\r\nIntro\r\nAbout 3 weeks ago we reported in Checkmarx blogpost of an attacker experimenting in several techniques while\r\nattempting dependency confusion attacks. In the past week, research teams from JFrog and Sonatype have also\r\npublished blog posts informing the community about hundreds of malicious packages. The 3 reports are all related\r\nto the same threat actor.\r\nThe same attack actor appears in all reports, tracked as RED-LILI by Checkmarx SCS research team, has recently\r\nautomated the process of creating NPM users along with package publication.\r\nCheckmarx SCS research team was tracking RED-LILI’s activity since it was first discovered internally on 2022-\r\n02-23 by its automated software supply chain attack detection systems. During this time, and until today, the team\r\nstudied this attack actor’s capabilities and techniques, while continuously disclosing the findings to NPM security\r\nteam.\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 1 of 16\n\nMultiple disclosure emails sent to NPM security team, informing them about RED-LILI’s activity\r\nThroughout the attacker’s experiments iterations, the packages’ functionality itself remained mostly unchanged.\r\nSpecifics about the code, its likely origin, and other interesting details can be found in our previous blog.\r\nToday, we want to shed some additional light on this new and intriguing technique. We looked at the attacks, put\r\nthe pieces and clues together, and tried to assemble a likely outline of the attacker’s automation. In addition, we\r\ncan report that this threat actor has published ~800 packages via a fully automated system, responsible for creating\r\nNPM user accounts, and publishing packages while passing OTP (One Time Passwords) verification requests.\r\nMotivation\r\nAs mentioned above, threat actor RED-LILI is experimenting and testing new techniques that might help them to\r\navoid detection and reach bigger distribution.\r\nWe cannot, of course, be sure of this attacker’s intentions, but a possible motivation for this new experiment is to\r\nprolong the time the published packages are “alive” on the NPM registry before they are detected and taken down.\r\nCustomarily, an attacker would open an anonymous NPM account and publish all or most of their packages under\r\nthis user account. One of the downsides of this is the fact that once one of the malicious packages is detected it is\r\nlikely that all of the other packages under this user account will be detected as part of an investigation and will be\r\ntaken down as well. This new technique (user account per package) goes into some effort to avoid a situation\r\nwhere the package is taken down for as long as possible.\r\nPicking The Attacker’s Breadcrumbs\r\nThe initial curiosity toward this cluster of malicious packages was in light of the scale and frequency of the\r\nattacks. The attacker published ~800 packages, most of them having a unique user account per package, in bursts\r\nover the span of roughly a week. While the packages names were methodically picked, the names of the users\r\npublishing them were randomly generated strings such as “5t7crz72” and “d4ugwerp”. This is uncommon for the\r\nautomated attacks we see. Usually, attackers create a single user and burst their attacks over it. From this behavior,\r\nwe can conclude that the attacker built an automation process from end to end, including registering users and\r\npassing the OTP challenges.\r\nThe Server Behind the Scenes\r\nThe first breadcrumb in the first wave of the attack is the domain “rt11[.]ml”. It is pointing to the primary server\r\nof the attacker and this domain appears in the email address of the dummy users created in order to publish the\r\npackages. In addition, this domain is used as the target server address to which the data is being sent to.\r\nLater down the road, a new domain was registered “33mail[.]ga” and took the place of the former domain\r\n“rt11[.]ml”. It is likely that both domains were acquired free of charge by Freenom service.\r\nLooking closer at this server reveals that it appears to be hosted in a U.S. hosting company Multacom which is\r\nbased in California. We disclosed these findings to their NOC team as we believe this is one of their clients’\r\nactivities and that Multacom has no relationship to this other than leasing the server to the attacker.\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 2 of 16\n\nLooking more deeply, this server has interesting ports open:\r\nAn nmap scan result of the attacker’s server\r\nSince the server is listening to http/https, we checked what is being returned when browsing into this webserver.\r\nThe result you are seeing is the root page of the server version of Interactsh tool, hinting to us this is a self-hosted\r\nversion of the popular open-source tool:\r\nInteractsh\r\nInteractsh is an open-source tool for out-of-band “Data Extraction”, and is a tool originally designed to detect\r\nbugs that cause external interactions. The usage is quite simple, running Interactsh gives the operator a unique\r\nURL, which whenever interacted with it, audits the full details to the operator for later inspection. Interactsh\r\nsupports multiple network protocols, including HTTP, SMTP, DNS, and more.\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 3 of 16\n\nInteractsh can be used as-is. Zero configuration is needed for inexperienced users via the web application\r\napp.interactsh.com. And for the more advanced users, Interactsh is built to run self-hosted on a dedicated server\r\nwhich its operator has the option to customize advanced settings including supporting a custom domain\r\nPackage Name Picking\r\nAt first, the attacker’s name picking puzzled our research team. But after giving it another look, they were able to\r\nidentify a pattern. The attack actor specifically targeted the @azure NPM scope under and as it appears, the\r\nattacker extracted the package names and altered their names, erasing the scope part (‘@azure/’ in this instance) or\r\nreplacing it with a similar string (such as “azure-“) and doing their best effort in publishing non-taken packages\r\nunder scopeless, similar package names.\r\nThe Complete Picture\r\nNow that we have a deeper understanding of the technology stack and tools used in this attack, we rolled up our\r\nsleeves and start reproducing it by ourselves. This exercise was done solely for the purpose of learning the\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 4 of 16\n\nattacker’s challenges in implementing their system.\r\nServer\r\nThe initial building block is setting up a Virtual Private Server (VPS). This server will run on an AWS EC2\r\nmachine. So, we launched one and wrote down its assigned IP and domain address to use in the next DNS\r\nconfiguration.\r\nCustom Domain\r\nThe next ingredient is our own domain. We purchased the “malpkg.site” domain which we used as the primary\r\ndomain pointed at our dedicated server.\r\nSetting up the domain’s DNS records was quite straight forward as documents in Interactsh official\r\ndocumentation. In addition to the regular A record, we also configured the NS record to support the DNS\r\ntunneling functionality for data exfiltration.\r\nInteractsh Server\r\nAs mentioned above, Interactsh is an open-source project written in Go. It has a client application and a server\r\napplication. The former can be installed from its source code using “go install” command or by downloading a\r\nmatching precompiled version from the project’s releases page.\r\nThe configuration of Interactsh server is straight forward. Since our server is hosted on AWS, and is assigned with\r\na private IP address, we had to configure it with the public IP “-ip”. The domain flag “-domain” was also needed\r\nto instruct the server what name needed to issue an SSL certificate for. In addition, we wanted to add a token-based authentication between the client and the server, so we defined a token string as we ran the server. While\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 5 of 16\n\nexperimenting the connectivity with the client, we saw the default client id was quite long, so changing the “-cidl”\r\nand “-cidn” flags made it possible to shorten the client id. Note that this needs to match in both server and client,\r\notherwise the data will not be synchronized properly.\r\nsudo ./interactsh-server -domain \u003cdomain\u003e -ip \u003cip address\u003e -e 1 -t \u003cauthentication token\u003e -debug -cidl 9 -cidn\r\nOnce we got all the configurations in order, we had our own interactsh server linked to our new domain.\r\nInteractsh Client\r\nThe next building block was to configure the Interactsh client with proper communication to the server to\r\nconclude the infrastructure phase. But before we go on to that, there is one more interesting detail that lies in this\r\nserver-client connection.\r\nIf not specified when running Interactsh server, it will allow connections from clients with no validation. This\r\nmeans that if our attacker ran their server in that manner, we would be able to connect to it and possibly gain\r\naccess to interesting information. This hope had quickly faded since the attacker seems to use the “-a” or “-t” flags\r\nin the server run command, which means that access to it will be granted only to the client providing the correct\r\nauthentication token.\r\nSetting up the client and its connection to the server is fairly simple. The following command is what we’ve used\r\nto connect to our server:\r\ninteractsh-client -s \u003cdomain\u003e -v -t \u003cauthentication token\u003e -cidl 9 -cidn 4\r\nAnd that is it! Our infrastructure is up and running. Next building block: Automation script.\r\nThe Main Tool\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 6 of 16\n\nThe real magic is harnessing Interactsh as a building block with automation. I have written an internal tool in\r\nPython for research purposes, simulating the steps done the attack group. Partial code snippets from this tool are\r\nreferenced below.\r\nGetting started with the development, the following major building blocks came to mind:\r\nCreating NPM accounts\r\nEmail OTP Challenges\r\nPublishing NPM packages\r\nFinding candidate package names under the targeted scope\r\nFinding candidate package names under the targeted scope\r\nAs seen performed by the attacker, I’ve added a functionality to list per given scope name, all packages under it,\r\nwhile manipulating and permutating the package’s name to the best-effort. The function iterates over a search API\r\ncall to https://registry.npmjs.com/-/v1/search :\r\nCreating NPM Accounts\r\nThe building block has no intentions to be exposed as API. Think about it – why would NPM encourage the\r\ncreation of users automatically?\r\nHere, I had to use some of my browser-based automation hacks, equipped with tools like Selenium and some\r\ncustom Python code. I was on my way to wrap the signup form, interact with input fields and some buttons, all to\r\nsimulate user actions in the flow of NPM’s user creation.\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 7 of 16\n\nHere is the information required in the form to create an NPM user account:\r\nUnique Username – used Interactsh’s client id\r\nEmail Address – \u003cclient id\u003e@\u003cclient id\u003e.\u003cmy domain\u003e\r\nStrong password – 12 characters random generated\r\nOne Time Password (OTP) Challenges\r\nTo deal with bots and verify the validity of the email address, NPM added a challenge to the user with an OTP\r\nsent to the email address as the last step of the registration process.\r\nThe challenge to extract the OTP from the email sent by NPM to the user’s email “\u003cclient id\u003e@\u003cclient id\u003e.\u003cmy\r\ndomain\u003e” was quite interesting.\r\nWrapping Interactsh-client executable was quite fun. I chose to tap into the stdout stream as the executable has the\r\noption to write JSON structures line-by-line, which can be easily parsed\r\nTo help with this task, I’ve created a class called InteractshClient, responsible to wrap the functionality of the\r\nexecutable in a neat way.\r\nOnce a session is started, the server generates a client id and from it the username and email address are\r\nconstructed under our domain “malpkg.site”. Next is initiate the sign-up process by calling _create_npm_user()\r\nfunction.\r\nDuring this function, a hidden browser is launched using Selenium and the matching ChromeDriver.  After\r\ninteracting with the form fields, NPM servers sends the OTP email via SMTP protocol to the user’s email address,\r\nresulting in the user’s email address being sent to my Interactsh server (e.g. \r\nc90ehc8ngyaer@c90ehc8ngyaer.malpkg.site). This data can be queried using the wrapped InteractshClient\r\nmentioned above like so:\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 8 of 16\n\nPublishing NPM Packages\r\nNow that we have our brand-new user account on NPM, we can continue to create and publish our malicious\r\npackage, all automatically of course. Adhering to what the attacker seems to do.\r\nFirst step is to sign-in with the NPM account, using the “npm login” command, which creates a global token in the\r\n.npmrc file. This token is used when the following command “npm publish” is being executed.\r\nThe flow is quite simple, and interacted with the command stdout-stdin streams. The main concept is to answer 4\r\nquestions asked:\r\nUsername\r\nPassword\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 9 of 16\n\nEmail address\r\nOTP challenge\r\nAs you may guess, all building blocks already setup and can be re-used. Since the same OTP email is sent, we can\r\nuse the same function that parses the OTP from interactsh-server incoming email. The function looks like so:\r\nLast step is to create a temporary directory, and drop 2 files there:\r\npackage.json – simple declaration of the package and instruction to run the main.js file upon installation\r\nindex.js – will contain the JavaScript payload provided by the operator, will execute automatically upon\r\npackage installation\r\nThis is accomplished using the following code:\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 10 of 16\n\nThat’s it! Now we have an automated process of publishing NPM packages, end-to-end, fully automated from\r\nNPM accounts generated on the fly.\r\nAccess Tokens to Bypass 2FA\r\nIt is worth mentioning that once the NPM user account was created, it is possible to configure it in a way that does\r\nnot require an email OTP challenge in order to publish a package. This could be done by generating an Access\r\nToken in the settings page having the 2FA requirement disabled.\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 11 of 16\n\nNPM’s settings page – have an option to bypass OTP challenge choice of authentication levels\r\nWe presume that this is the way attackers who publish bursts of malicious packages were able to automate their\r\nprocess without setting up the described mechanism.\r\nTimeline\r\nNovember 2021 – Around 500 malicious packages were published from 4 different NPM user accounts,\r\nnow identified as related to RED-LILI.\r\nFeb 23 – package “cspell-version-pin” was uploaded and unpublished a day later (probably by the author).\r\nUploaded from the username “the_ghost-1” with the email address the_ghost-1@wearehackerone.com\r\nExfiltrating information to domain first seen “rt11.ml”\r\nFeb 23 – A certificate was issued by Let’s Encrypt to ”rt11.ml” domain\r\nMarch 1 – NPM package “glints-sdk” was published\r\nContains obfuscated malicious code\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 12 of 16\n\npublished under the username ‘babylon7’\r\nExfiltrating information to domain “rt11.ml”\r\nMarch 6 – 5 NPM packages and one PyPi package published. A detailed account regarding those packages\r\ncan be found in our blog. This phase of experiments included code obfuscation and obviously an attempt to\r\nact on PyPi as well.\r\nMarch 10, 11, and 14 – The attacker used several usernames with the prefix “the_ghost-“ to publish a bulk\r\nof packages. In addition to that they used the username ‘chandannaidu400’ to publish dozens of empty\r\npackages.\r\nMarch 15 – NPM packages “kusto-language-service” and “lorawan-devices” published from two sperate\r\nusernames “kusto-lang” and “lorawandevices” respectively.\r\nMarch 20 – A burst of ~600 NPM packages were published, fully-automated as described above\r\nMarch 27 – A certificate was issued by Let’s Encrypt to “33mail.ga” domain and the Interactsh-server app\r\nwas re-configured from the domain rt11.ml to 33mail.ga\r\nMarch 27 – ~90 new versions “99.10.13” to existing NPM packages, The main change was updating the\r\nnew data exfiltration endpoint (425a2[.]33mail[.]ga)\r\nAcross the timeline – continuous disclosure to NPM, PyPi, Multacom\r\nInspection of the SSL certificates used by the attacker\r\nRED-LILI’s Profile\r\nExamining the packages’ code deeply, reveals that there are some obvious unique identifiers to the attacker’s lab\r\nthat helps distinguish RED-LILI’s packages from others. As it seems, these are the results of checks that are done\r\nto avoid running the malicious payload on the attacker’s lab machines, Among these indicators, we found:\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 13 of 16\n\nDESKTOP-4E1IS0K (windows computer name, security scanner)\r\nlili-pc (hostname)\r\naws-7grara913oid5jsexgkq (aws hostname)\r\nD:TRANSFER (path, windows format)\r\n/root/node_modules/ (path, linux format)\r\n/home/node (linux username “node”)\r\ndaasadmin (username)\r\nbox (hostname, security scanner)\r\ninstance (hostname, security scanner)\r\nScreenshot of the malicious payload, with the “do not run” identifiers\r\nIOC’s\r\nthe_ghost-1@wearehackerone.com\r\nrt11.ml\r\nrt11.33mail.com\r\n33mail.ga\r\n216.127.184.168\r\nConclusion\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 14 of 16\n\nIn total, Checkmarx SCS team has detected ~1500 malicious packages published by RED-LILI. The packages\r\nwere all disclosed to the NPM and PyPi security teams as well as to the service provider hosting the attacker\r\ninfrastructure Multacom.\r\nUntil this incident, we’ve witnessed that most attack actors publishing malicious payloads at scale doing things\r\nsemi-automatically. This one is doing it on FULL-AUTO.\r\nAs supply chain attackers improve their skills and make life harder for their defenders, this attack marks another\r\nmilestone in their progress. By distributing the packages across multiple usernames, the attacker makes it harder\r\nfor defenders to correlate take them all down with “one stroke.” By that, of course, making the chances of\r\ninfection higher.  \r\nIMHO package managers need to set up more security measures such as integrating Captcha to the user creation\r\nforms to deal with bots implementing such automation systems.\r\nFull list of Packages\r\nSharing a full list of the related packages, with ~1500 packages.\r\nTags:\r\nAppSec\r\narticle\r\nawareness\r\nCheckmarx Security Research Team\r\nDeveloper\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 15 of 16\n\nEnglish\r\nSupply Chain Security\r\nSource: https://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nhttps://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/\r\nPage 16 of 16",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MISPGALAXY",
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://checkmarx.com/blog/a-beautiful-factory-for-malicious-packages/"
	],
	"report_names": [
		"a-beautiful-factory-for-malicious-packages"
	],
	"threat_actors": [
		{
			"id": "04a3b6fd-6e6b-4d80-bb21-6bba92c3d747",
			"created_at": "2023-11-30T02:00:07.297169Z",
			"updated_at": "2026-04-10T02:00:03.483935Z",
			"deleted_at": null,
			"main_name": "Red-Lili",
			"aliases": [],
			"source_name": "MISPGALAXY:Red-Lili",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434523,
	"ts_updated_at": 1775826725,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/99682021e4711f7e1b8404a27bb34fdc11b3a742.pdf",
		"text": "https://archive.orkl.eu/99682021e4711f7e1b8404a27bb34fdc11b3a742.txt",
		"img": "https://archive.orkl.eu/99682021e4711f7e1b8404a27bb34fdc11b3a742.jpg"
	}
}