Fake LinkedIn recruiter's coding test hides a RAT and wallet stealer

A recruiter reached out to a friend of the article's author on LinkedIn, offering a part-time remote software-engineering role at good hourly pay that matched the friend's prior experience closely. After only a couple of messages, the process skipped straight past any introductory call to a coding test, sent from a personal @gmail.com address rather than an official company one, and the recruiter's own LinkedIn profile did not show up as part of the company. The company named in the outreach had nothing to do with it: it was impersonated without its knowledge, and it has since posted on LinkedIn to explain that the offer did not come from it. The fake recruiter's LinkedIn profile has since been deleted.
The test itself was a TypeScript project of about 180 files on Bitbucket, unobfuscated and unminified, mixing dead code with working code so that one suspicious detail was easy to miss inside the noise: a call out to an external jsonbin.io endpoint. That call ran automatically the moment the project was started, through npm run dev or npm start, before any actual test-solving began. The code that ran first had access to Node's require function, so it could pull in child_process to shell out, fs to read, walk and write to the filesystem, and net or https to open its own exfiltration channel, and it could read process.env directly, which in this project exposed values including MONGO_URI, JWT_SECRET, SENDGRID_API_KEY, CLOUDINARY_API_SECRET and PAYTM_MERCHANT_KEY.
The jsonbin.io endpoint's response turned out to be a remote-code-execution loader: 24,686 characters of obfuscator.io-obfuscated JavaScript wrapped around a small webpack bundle. Deobfuscating it produced more obfuscated code that pulled further instructions, behind a JWT-authenticated request, from a command-and-control server at 147.189.174.138. That exchange ultimately delivered four separate modules.
The first module, scdata, is an interactive remote-access trojan: node-pty gives it a full shell, ssh2 lets it pivot to other systems and steal PEM keys, screenshot-desktop with sharp captures the screen, clipboardy reads the clipboard, and @nut-tree-fork/nut-js simulates keyboard and mouse input; it also checks whether it is running on a virtual machine or bare metal. The second, ldata, is a browser credential and crypto-wallet stealer: across Chrome, Edge, Brave and LT on Windows, macOS and Linux, and across every browser profile, it reads Login Data and Web Data files, Local Extension Settings LevelDB stores and macOS's login.keychain, and it can target 28 wallet browser extensions: 10 of them named as examples, MetaMask, Phantom, Coinbase, Binance, TronLink, Trust, Keplr, Coin98, OKX and Rabby, plus 18 more. It loops indefinitely, re-uploading roughly every minute. A third module, a file grabber, walks the home directory for private keys, secret phrases, anything matching metamask, bitcoin or solana, .env files, *.pem, *.p12 and *.pfx files, documents and images, and the entire .ssh, .aws, .gnupg and .docker directories, and on Windows it also enumerates every drive letter through PowerShell. The fourth, a clipboard monitor, polls the clipboard continuously and beacons its contents out while hiding behind the log name npm-compiler.log.
None of this needs administrator rights. SSH keys, cloud credentials, browser profiles, wallet data and .env files are all owned by the victim's own user account by design, since people need to read them routinely, so a process started under that account already inherits everything it needs; running the malware is no different, technically, from running cat ~/.ssh/id_rsa from a shell. The network side is outbound-only: the infected machine connects out to the command-and-control server on port 7321, so the server simply sees the source address on the accepted connection the way any web server sees a visitor, with no scanning or address registration required. That design keeps working behind NAT, CGNAT, a corporate proxy or a home router, and it does not matter if the victim's IP address changes.
The RAT actively checks for virtualization: it runs system_profiler, reads /proc/cpuinfo, and greps for strings like vmware, qemu and microsoft corporation, then tags its outgoing beacon (VM) or (Local). The article's author reasons that this flag most likely feeds the attackers' own triage of victims, since a sandboxed VM is more likely to belong to a researcher and less likely to hold a real wallet worth draining.
The author tested three lines of defense and ranked them from weakest to strongest. Asking an AI assistant to scan the project for anomalies is only a partial protection: it can flag an unusual call to an external endpoint like jsonbin.io, but it cannot see what that endpoint actually returns; specifically, Claude Code did not detect anything strange when simply prompted to scan the codebase for unusual patterns. Running the code only inside Docker, without ever mounting host data into the container, isolates the host and keeps secrets safe. The strongest option tested was a fully isolated virtual machine, for example through Vagrant, snapshotted before running the code and restored afterward; even then, without a desktop environment, the modules that leak browser data or take screenshots become self-limiting, though the remote-access trojan and file grabber still work.
The author's suggested response for anyone caught by this, offered as something a victim probably should do rather than a guaranteed fix, is to revoke and rotate SSH keys, change passwords, check for any other plaintext secrets that need to change, and reinstall the operating system entirely.
Key facts
- A LinkedIn 'recruiter' impersonating a real company, contacting from a personal @gmail.com address, skipped the usual introductory call and sent a friend of the article's author straight to a roughly 180-file TypeScript coding test hosted on Bitbucket.
- Starting the project, via npm run dev or npm start, silently called an external jsonbin.io endpoint that returned a 24,686-character obfuscated loader, which pulled further code from a command-and-control server at 147.189.174.138 behind a JWT-authenticated request.
- The payload installed four modules: an interactive remote-access trojan (full shell, SSH pivoting and PEM-key theft, screen capture, simulated keyboard and mouse input), a stealer that can target 28 browser crypto-wallet extensions including MetaMask, Phantom and Coinbase, a file grabber for SSH keys, cloud credentials and secret phrases, and a clipboard monitor disguised under the log name npm-compiler.log.
- None of it required administrator rights, since SSH keys, browser data and .env files are already owned by the victim's own account by design; the remote-access trojan also fingerprints virtual machines and tags its beacon (VM) or (Local), which the author reads as a signal for the attackers' own triage.
- Asking an AI, specifically Claude Code, to scan the project for anomalies missed the attack; the author found a fully isolated, snapshotted virtual machine, via Vagrant, the strongest tested defense, and recommends rotating SSH keys and passwords and reinstalling the OS after exposure.
Why it matters
This documents a working chain that turns an ordinary LinkedIn recruiter message and a take-home coding test into a full system compromise. No exploit or vulnerability is needed; running the project through its own normal startup command, npm run dev or npm start, is enough to trigger the first-stage call and the loader chain behind it. Because the project itself looks ordinary, about 180 files, no obfuscation or minification, a mix of dead and working code, the one suspicious detail is easy to miss for anyone reviewing it the way they would review any other take-home assignment.
Who it affects
Anyone job-hunting on LinkedIn who is likely to run an interview coding challenge directly on their own machine is a direct target, especially anyone holding SSH keys, cloud or API credentials (the piece's own example environment variables include MONGO_URI, JWT_SECRET, SENDGRID_API_KEY, CLOUDINARY_API_SECRET and PAYTM_MERCHANT_KEY), browser-saved passwords, or one of the 28 targeted crypto-wallet browser extensions, among them MetaMask, Phantom, Coinbase, Binance, TronLink, Trust, Keplr, Coin98, OKX and Rabby. The company named in the outreach was impersonated without its knowledge and has since had to publicly clarify on LinkedIn that it was not involved.
How to use it
There is no product here, only a defensive checklist. Before running any interview take-home project, check whether the outreach came from an official company account rather than a personal address, whether a normal introductory call happened before the test arrived, and whether the test's language actually matches the role. The author ranks the available isolation options from weakest to strongest: asking an AI assistant to scan the code catches obvious anomalies like an external endpoint call but not what it returns; running the project only inside Docker, without mounting host data into the container, is stronger; a fully isolated virtual machine, snapshotted before running the code and restored afterward, is the strongest option tested, though even a clean VM without a desktop still lets the remote-access trojan and file grabber run.
How solid is it
The account is a first-hand technical writeup: the author describes pulling the loader's response, deobfuscating it, and reading out the exact command-and-control IP address and port, the obfuscated payload's size in characters, and the specific npm packages each module is built from. Some details are inherently unverifiable from outside the writeup itself: the impersonated company, the fake recruiter and the friend who was targeted are all left unnamed, and no CVE identifier, victim count or financial-loss figure is given, so this documents the mechanics of one attempted compromise rather than the measured scope of a campaign.
Risks and caveats
The write-up covers one incident, one friend's coding-challenge interview, not a measured campaign: there is no victim count, no financial-loss total and no CVE identifier. The recommended response after exposure, revoking and rotating SSH keys, changing passwords, checking for other plaintext secrets and reinstalling the operating system, is offered as something a victim probably should do, not stated as a guaranteed-sufficient fix. The author's own explanation for why the malware tags its beacon (VM) or (Local), that attackers likely deprioritize sandboxed machines because they are less likely to hold real wallets, is presented as the author's own reasoning, not a confirmed fact about how the operators behave.
“You opened the door to hell while you just wanted to get a job.”
— the article's author