new (Function.constructor)() — eval() in a suit
How a “Job Offer” on LinkedIn Turned Into a Malware Investigation
new (Function.constructor)() — eval() in a suit
How a “Job Offer” on LinkedIn Turned Into a Malware Investigation
THE OFFER
It started the usual way. A connection request on LinkedIn, a profile with eight years of history, a real-looking name, a real-looking photo. The kind of profile that passes the two-second scroll test. We had the standard exchange — your skills are a great fit, we have competitive compensation, very exciting project. Naturally.
The only thing that stood out, if you looked closely: the account had a long gap between its early activity and today. Eight years old on paper, but quiet for most of them. A detail easy to overlook when someone is offering you interesting work.
The task was simple. Clone a repository, complete a small assignment, open a pull request. The repository was hosted on Bitbucket under a workspace called “tech_workspace”. The project name: YAMTOKEN — a fabricated name, deliberately chosen to sound like a real DeFi protocol. A crypto trading platform, because that adds an extra layer of plausibility for a developer audience — and because developers tend to have interesting things on their machines. Passwords, SSH keys, API tokens, infrastructure access. The crypto angle was bait, but the goal was everything.
FIRST LOOK: NOTHING TO SEE HERE
The repository looked clean at first glance. A standard React frontend bundled into a single JS file — Redux, Material UI, Axios, nothing unusual. The backend address pointed at localhost. The package.json listed familiar dependencies. Lifecycle scripts — preinstall, postinstall, prepare — were empty. No obvious red flags.
A few dependencies raised questions — packages with no visible use in the codebase, imported nowhere, with no obvious reason to be there. They turned out to be legitimate. Just noise, probably placed to make the dependency list look more credible. It took time to verify that, which was presumably the point.
A deeper static scan of the server code found something more interesting: a single file stood out — server/middleware/errorHandler.js.
THE BACKDOOR
A quick note on the attack surface before we get to the code. Most developers know that eval() is dangerous — it executes an arbitrary string as JavaScript, and any competent static analysis tool or code reviewer will flag it immediately. Attackers know this too. So instead of eval(), this backdoor used new (Function.constructor)(‘require’, code)(require). Functionally identical: pass it a string, get it executed as JavaScript with full access to Node’s module system. But it looks different enough on the page that it can survive a casual review without raising alarms. Consider it eval() wearing a suit.

The file had two functions. The first — errorHandler — was the execution engine: it accepted a string and ran it as server-side code with full access to the filesystem, network, and process.
The second — errorTimeHandler — was the delivery mechanism. On startup, it read three values from environment variables, decoded them from base64, and made an HTTP GET request to the decoded URL with decoded authorization credentials. The response was passed directly into errorHandler and executed.

So the full chain was: start the server → call a remote URL → receive arbitrary JavaScript → execute it with full Node.js privileges. A textbook remote code execution backdoor, with the C2 address hidden in base64 inside an .env file.
The function name errorTimeHandler was a nice touch. It sounds like something a developer might write when handling timed-out error callbacks. It does not sound like something that phones home to a command-and-control server on every server start.
WHERE IT WAS HIDDEN
The call to errorTimeHandler() was located in server/routes/api/profile.js — a standard Express.js route file for managing user profiles. One line, placed between two unrelated route definitions, in the middle of a 250-line file.
The base project, it turned out, was DevConnector — a widely-used MERN stack tutorial project by Brad Traversy, known to hundreds of thousands of developers from his Udemy and YouTube courses. The attackers took a codebase that developers recognize and feel comfortable with, and inserted a single line. A developer reviewing this code would likely recognize the structure and move on. The trap was in counting on that familiarity.
THE PAYLOAD
The .env file contained the actual C2 address, base64-encoded:
The 607 at the end is a victim ID. The server generates a personalized payload for each target — five samples collected during the investigation all had different sizes and different checksums. The URL pattern ipcheck indicates that the server also logs the victim’s IP on every connection.
The payload itself arrived as a 3.4 megabyte blob of heavily obfuscated JavaScript. After deobfuscation, the actual logic was compressed to around 163 kilobytes. What it contained was a fully functional Remote Access Trojan.
On execution, the payload launched three independent background worker processes with lock files to prevent duplication. Each worker had a specific role:
The first worker targeted browser-stored credentials — saved passwords across all major browsers, decrypted using platform-native methods on Windows, macOS, and Linux.
The second worker scanned the filesystem recursively, collecting anything that looked like credentials: private keys, seed phrases, SSH keys, API tokens, crypto wallet files, and browser extension data for every major wallet. Files were uploaded to the C2 in batches.
The third worker established a persistent WebSocket connection to the C2, keeping an open real-time channel through which the attacker could issue arbitrary shell commands, request directory listings, trigger file uploads, or kill and restart the other workers.

Additionally, the payload monitored the system clipboard every second and sent its contents to the C2. On all three platforms.
All three processes were detached from the parent, suppressed all output, and respawned automatically every five hours. None of this would produce any visible output. The developer’s terminal would show the application starting normally.

This was not a quick script written for one job. The code was structured, tested, and maintained.
THE INFRASTRUCTURE
The C2 infrastructure had multiple layers.
The staging server — walter-server.vercel.app — served as the initial payload delivery point and victim registration system. The actual command-and-control server ran at a dedicated IP on three separate ports: one for credential uploads, one for file uploads, and one for the real-time command channel. As of the date of this investigation, all three ports were live and responding. The infrastructure was fully operational.

According to WHOIS data, the IP belongs to a subnet associated with Cloudzy — a VPS provider that, according to a 2023 Halcyon report, was found to be hosting infrastructure for multiple APT groups simultaneously. The parent network is registered to FranTech Solutions, widely referenced in security research as a provider that is unresponsive to abuse complaints. Whether the hosting choice was deliberate is an inference, but the combination suggests an infrastructure selected with longevity in mind.
One more detail. The codebase contained a commented-out backend URL: dispossessor.com. A whois lookup on that domain returned the following nameservers:

The nameservers suggest the domain was seized by the FBI at some point. Whether that was related to this campaign or something else entirely is unknown. The domain appears in the codebase as a previous backend URL — what that implies about the timeline is a matter of speculation.
WHAT THIS ATTACK IS
Let me be clear about what this is, because “targeted malware via fake job offer” can sound abstract.
A developer who received this offer, cloned the repository, and ran the application would have immediately and silently installed a trojan. No warning. No visible output. The terminal would show the application starting normally.
It does not matter what the developer worked on. Every saved password in every browser — banking, corporate accounts, email, everything — would be extracted and uploaded. Every SSH key on the machine. Every API token in any .env file. Every seed phrase or wallet file if present. The clipboard content from the moment of infection onward. And a permanent remote shell left open for whatever comes next.
The social engineering was patient and credible. The technical payload was sophisticated, cross-platform, and clearly maintained. The infrastructure was deliberately hardened against takedown. The delivery was designed for developers because developers are a high-value target — but the payload made no distinction between a crypto wallet and a corporate VPN credential. It wanted all of it.
The single line errorTimeHandler() in a familiar-looking file is what the entire operation balanced on. One line, in one file, in a project most of the targets would recognize and feel at home in.
That is a well-constructed attack. Whoever built this knew what they were doing, knew who they were going after, and had done it before.
RECOMMENDATIONS
If you are a developer — any kind of developer — who receives unsolicited work offers:
Do not run code from unknown sources on your primary machine. Ever. Not even to “just look at it quickly.” A Docker container with no network access and no mounted volumes is the minimum baseline for evaluating unfamiliar repositories.
Treat unsolicited technical assessments from new contacts as a risk vector, not an opportunity. Verify the company through official channels before engaging. One repository on a personal account on any git hosting platform is not a company.
If you have already run something like this, assume compromise. Change all credentials, revoke all API keys, transfer crypto assets to fresh wallets generated on a clean machine.
The people who built this are patient. They can afford to be.
메타데이터
- post_id
- 77046a16edf7
- slug
- new-function-constructor-eval-in-a-suit-77046a16edf7
- url
- https://medium.com/@fogbitex/new-function-constructor-eval-in-a-suit-77046a16edf7
- canonical_url
- https://medium.com/@fogbitex/new-function-constructor-eval-in-a-suit-77046a16edf7
- author_url
- https://medium.com/@fogbitex
- status
- ok
- fetched_at
- 2026-06-09 21:21:26