UNPKG

worm-sign

Version:

A prescient scanner to detect and banish Shai Hulud malware from your dependencies.

74 lines (73 loc) 2.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EntropyCalculator = void 0; exports.calculateEntropy = calculateEntropy; exports.calculateEntropyStream = calculateEntropyStream; exports.isHighEntropy = isHighEntropy; /** * Shannon Entropy Analysis * * This module calculates the Shannon entropy of strings to detect * high-entropy content, which is often indicative of packed or * obfuscated malware payloads (e.g. bun_environment.js). */ class EntropyCalculator { frequencies = {}; totalBytes = 0; update(chunk) { const len = chunk.length; this.totalBytes += len; for (let i = 0; i < len; i++) { const byte = typeof chunk === 'string' ? chunk.charCodeAt(i) : chunk[i]; this.frequencies[byte] = (this.frequencies[byte] || 0) + 1; } } digest() { if (this.totalBytes === 0) return 0; let entropy = 0; for (const count of Object.values(this.frequencies)) { const p = count / this.totalBytes; entropy -= p * Math.log2(p); } return entropy; } } exports.EntropyCalculator = EntropyCalculator; /** * Calculates the Shannon entropy of a string. * Formula: H(X) = - sum(P(xi) * log2(P(xi))) * * @param str The input string * @returns The entropy value (typically between 0 and 8) */ function calculateEntropy(input) { const calculator = new EntropyCalculator(); calculator.update(input); return calculator.digest(); } /** * Calculates entropy from a readable stream. */ function calculateEntropyStream(stream) { return new Promise((resolve, reject) => { const calculator = new EntropyCalculator(); stream.on('data', (chunk) => calculator.update(chunk)); stream.on('error', reject); stream.on('end', () => resolve(calculator.digest())); }); } /** * Checks if a string has suspiciously high entropy. * * @param str The string to check * @param threshold The threshold (default 5.2 based on research) * @returns True if entropy exceeds threshold */ function isHighEntropy(str, threshold = 5.2) { // Short strings can have artificially high or low entropy and are less likely to be packed payloads if (str.length < 50) { return false; } return calculateEntropy(str) > threshold; }