Three fake interviews, three malware repos
Every "take-home task" I scanned this year tried to run malware the moment the folder was opened. What they had in common, how to protect yourself, and how to scan a repo before you touch it.
TL;DR: If a recruiter sends you a repository to “review”, “fix” or “run locally”, treat it like an email attachment from a stranger. In all three cases below, the malware ran when the folder was opened or when tooling loaded a config file. Nobody needed to type
npm start. Scan before you open (for example with devguard-scanner), but never rely on a scanner alone.
Contents</summary>
- Background
- The three cases at a glance
- The playbook
- How to protect yourself
- If you already opened one
- Scanning with devguard-scanner
- Why you shouldn’t rely on it alone
- Help build it
</details>
Background
This year I went through several “interviews” for blockchain and Web3 developer roles. The pattern was always
similar: a friendly recruiter on LinkedIn or Telegram, a short call, then a repository to clone and get running
(“just check it works and tell us what you’d improve”).
I scanned each repository statically, without executing anything, before opening it. Three of them were
malicious. Each used a different trick, but the goal was the same: run code on the developer’s machine as early
and as quietly as possible, then steal credentials and crypto wallets.
About the company names: these are the companies the recruiters claimed to represent. Attackers
routinely impersonate real, reputable companies to look credible. Nothing here suggests the real organizations
were involved. If a real company’s name is used against you, tell that company. They usually want to know.
The three cases at a glance
April 2026
June 2026
October 2026
Claimed company
“Softstack”
“Yuga Labs”
“Dream Tech”
Repo theme
Platform MVP (web game)
NFT / Web3 front end
“Decentralized AI Agent Marketplace”
Trigger
VS Code task, runOn: folderOpen, plus an npm prepare hook
tailwind.config.js, loaded by build tooling and editor extensions
VS Code task hidden in settings.json instead of tasks.json
Hiding trick
Hidden terminal (echo: false)
Code pushed off-screen by 1,326 spaces, then obfuscated
Hidden terminal, then deletes the trigger and .git
Payload
curl \| bash from a free-hosting URL made to look like VS Code settings
Obfuscated JavaScript loader
Three-stage Node.js infostealer + remote-access trojan
Scan verdict
BLOCK: 2 critical, 2 high
BLOCK: 2 critical
Malicious (full manual teardown)
The October one is the most complete, so I took it apart down to the decrypted payload. It steals saved browser
passwords and cards from 13 browsers, the data of 40 crypto-wallet extensions, the macOS keychain, SSH keys,
.env files and anything named like a secret. It also logs your clipboard every second and opens a remote shell
for the attacker. The full low-level analysis, with IOCs and hashes, is here:
Is VS Code safe for a repo you never run?
The playbook
Recruiter outreach "Take-home task" You open the folder Auto-execution Theft
LinkedIn / Telegram ──▶ Web3 / crypto repo ──▶ (or install deps) ──▶ IDE task, config file, ──▶ passwords, wallets,
Discord / email one commit, new acct install hook, git hook SSH keys, .env, RAT
Stage
What attackers do
Red flags for you
Lure
A well-paid remote role, often Web3. A fast-tracked process. A real company impersonated.
Urgency. A new or thin recruiter profile. An email domain that doesn’t match the company.
Delivery
A GitHub or Bitbucket repo, or a zip. “Just run it and fix a bug.”
Being asked to run code before any real technical conversation. A one-commit repo from a throwaway account.
Trigger
Something that runs without you deciding to run it: .vscode/tasks.json or settings.json with runOn: folderOpen; package.json preinstall / postinstall / prepare; *.config.js files (Tailwind, Vite, PostCSS, ESLint, Next.js); git hooks; AI-assistant config.
Any .vscode/ folder in an interview repo. Lifecycle scripts. Huge or minified config files.
Hiding
Hidden terminals, code pushed off-screen with whitespace, obfuscation, payloads served remotely so the repo itself looks clean, self-deleting triggers.
Very long lines, echo: false / reveal: never, curl … \| sh, eval, new Function(...), base64 blobs.
Theft
Browser passwords and cookies, wallet extensions, keychains, SSH keys, .env files, the clipboard, then a remote shell.
By this point it’s too late.
The remote payload can change at any time. The repo often contains only a tiny loader, and the real malware
comes from a server that can serve different code per victim, per OS or per day. A “clean” repo today doesn’t mean
a clean repo tomorrow.
How to protect yourself
Before you touch the repo
- Verify the recruiter and the company through an independent channel: the official website, the careers page,
or a known employee. Don’t use links the recruiter sent you.
- Push back on “run it locally” as the first step. A real employer will happily walk through the code with you,
or give you a sandbox or codespace they control.
- Never clone or open it on your main machine, especially one with wallets, SSH keys, cloud credentials or an
unlocked password manager.
Inspect it safely
- Scan it without cloning, for example with
devguard scan https://github.com/owner/repo (see below).
- Read it in a plain viewer, such as the GitHub web UI with line wrapping on, or
less -S, rather than in your IDE.
- Check the auto-run spots first:
.vscode/tasks.json, .vscode/settings.json, .vscode/launch.json, .vscode/extensions.json
package.json scripts: preinstall, install, postinstall, prepare
- every
*.config.js, *.config.ts and *.config.mjs
.git/hooks, .husky/, .devcontainer/, Makefile, setup.py, pyproject.toml build hooks
- AI-assistant config (
.claude/, .cursor/, CLAUDE.md, AGENTS.md, MCP config), which can contain hooks or
instructions aimed at your coding agent
- Look for suspiciously long lines:
awk 'length > 300 { print FILENAME ":" FNR ": " length }' $(git ls-files)
Harden your editor
Add this to your user settings.json in VS Code, Cursor, Windsurf or any other fork:
{
// Never run tasks automatically on folder open
"task.allowAutomaticTasks": "off",
// Keep Workspace Trust on, and open unknown folders in Restricted Mode
"security.workspace.trust.enabled": true,
"security.workspace.trust.untrustedFiles": "prompt"
}
Tip: When VS Code asks “Do you trust the authors of the files in this folder?”, the answer for any
interview repo is No. Restricted Mode still lets you read the code. It just stops tasks, debuggers and many
extensions from running it.
If you really have to run it
- Use a disposable VM or cloud dev environment with no credentials, no wallets, no SSH keys and no access to
your home directory. Destroy it afterwards.
- Containers help, but don’t mount your home directory, the Docker socket or your SSH agent into them.
npm install --ignore-scripts (or the pnpm/yarn equivalent) closes one door. The October case shows it’s
not enough on its own: that attack never touched npm.
- Keep crypto in a hardware wallet, and never keep seed phrases as files or screenshots on a dev machine.
If you already opened one
Assume full compromise if one of these repos was opened and trusted in your IDE, or if its dependencies were
installed. Act from a different, clean device.
- Disconnect the affected machine from the network.
- Move your crypto first. Create new wallets with new seed phrases on a clean device, and transfer your
funds. Stealers drain wallets within minutes to hours.
- Change your passwords, starting with email, password manager, banking, GitHub/GitLab, cloud consoles, npm and
PyPI. Re-enroll 2FA.
- Sign out of all sessions everywhere. Stolen cookies get around both passwords and 2FA.
- Rotate every secret that was on the machine:
.env files, API keys, cloud credentials, DB passwords, deploy
tokens and SSH keys (remove the old public keys from servers and GitHub too).
- On macOS, change your login password, because the keychain may have been copied.
- If it’s a work machine, tell your security team right away. Company secrets may be exposed too.
- Reinstall the OS. A remote shell means arbitrary code ran, and you can’t confirm a clean state by hand.
- Report the recruiter’s profile and the repository to the platforms involved (LinkedIn, GitHub and so on).
Scanning with devguard-scanner
After the first one of these, I started building
devguard-scanner
(PyPI), and I used it for the scans above. It looks for exactly this
kind of attack:
- Auto-run triggers: IDE tasks, install and build hooks, config-as-code files, git hooks, AI-assistant hooks.
- Attack chains: it follows each trigger to the code it reaches. “Folder open → hidden obfuscated code” is
rated far worse than either one on its own.
- Capabilities: hidden or off-screen code, download-and-execute, browser and wallet data access, credential
theft, exfiltration.
It reads files as data and never executes anything.
pipx install devguard-scanner # or: uv tool install devguard-scanner
# Scan a GitHub repo WITHOUT cloning it: git never runs, so clone-time hooks can't fire,
# and the files never land in a folder your IDE could open
devguard scan https://github.com/owner/repo # add --ref BRANCH|TAG|SHA if needed
# Scan a local folder or an extracted zip
devguard scan path/to/repo
No install needed:
# Hosted API (public repos); Swagger UI at https://devguard-scanner.vercel.app/docs
curl -s 'https://devguard-scanner.vercel.app/v1/scans/github/owner/repo?format=md'
# Throwaway container
docker run --rm ghcr.io/yilmazhasan/devguard-scanner scan https://github.com/owner/repo --stdout md
You get a verdict, plus a Markdown report that lists each finding with its file and line, why it matters, when it
might be benign, and what to do next:
Verdict
Meaning
block
Do not open, install, or run it.
review
Read the report first.
indicators
Weak signals only, often benign.
no-indicators
Nothing found by the enabled checks. Not a guarantee.
A few other things it can do:
- An MCP server, so AI coding agents (Claude Code, Cursor, Copilot) can check a repo before they run its setup
commands. Agents are increasingly the ones typing
npm install.
- A CI or pre-commit gate: exit code
1 when findings reach --fail-on (default high).
- Optional AI explanations with your own provider key (Claude, OpenAI, Gemini or a local model). The AI output
is advisory only. It can’t change the verdict or hide deterministic findings.
Why you shouldn’t rely on it alone
No scanner can tell you a repo is safe, this one included.
- It’s static analysis. If the payload is downloaded or decrypted at runtime, it may only see the loader. In two
of the three cases above, the real malware wasn’t in the repo at all.
- Rules catch known techniques. Novel or heavily obfuscated malware can get past them.
- Dependencies aren’t downloaded and inspected unless they’re committed to the repo.
- Attackers read the same rules we write, and they adapt.
A no-indicators verdict means “nothing matched”, not “safe”. Use the scanner as one layer, together with
healthy suspicion, a hardened editor and a disposable environment.
Help build it
These campaigns change every few weeks: new trigger files, new hiding tricks, new loaders. One person can’t keep up
with that. devguard-scanner is open source (Apache-2.0), and contributions are very welcome.
- Share samples. If you got a malicious interview repo, open an issue. Defang URLs, and don’t post live payloads
publicly; see the security policy.
- Write detection rules for triggers and techniques that aren’t covered yet: new IDEs, build tools, package
managers, AI-agent config formats.
- Report false positives and false negatives. Both make it better.
- Add integrations: CI templates, editor extensions, LLM provider plugins.
- Spread the word. The best defense is a developer who knows this attack exists.
Repo: https://github.com/yilmazhasan/devguard-scanner ·
Issues: https://github.com/yilmazhasan/devguard-scanner/issues ·
Contributing: CONTRIBUTING.md
The more of us share what we see, the harder and more expensive this attack gets. If this post helps you spot one,
pass it on to a friend who’s job hunting.
About the company names: these are the companies the recruiters claimed to represent. Attackers routinely impersonate real, reputable companies to look credible. Nothing here suggests the real organizations were involved. If a real company’s name is used against you, tell that company. They usually want to know.
runOn: folderOpen, plus an npm prepare hooktailwind.config.js, loaded by build tooling and editor extensionssettings.json instead of tasks.jsonecho: false).gitcurl \| bash from a free-hosting URL made to look like VS Code settings.env files and anything named like a secret. It also logs your clipboard every second and opens a remote shell
for the attacker. The full low-level analysis, with IOCs and hashes, is here:
Is VS Code safe for a repo you never run? Recruiter outreach "Take-home task" You open the folder Auto-execution Theft
LinkedIn / Telegram ──▶ Web3 / crypto repo ──▶ (or install deps) ──▶ IDE task, config file, ──▶ passwords, wallets,
Discord / email one commit, new acct install hook, git hook SSH keys, .env, RAT
.vscode/tasks.json or settings.json with runOn: folderOpen; package.json preinstall / postinstall / prepare; *.config.js files (Tailwind, Vite, PostCSS, ESLint, Next.js); git hooks; AI-assistant config..vscode/ folder in an interview repo. Lifecycle scripts. Huge or minified config files.echo: false / reveal: never, curl … \| sh, eval, new Function(...), base64 blobs..env files, the clipboard, then a remote shell.The remote payload can change at any time. The repo often contains only a tiny loader, and the real malware comes from a server that can serve different code per victim, per OS or per day. A “clean” repo today doesn’t mean a clean repo tomorrow.
devguard scan https://github.com/owner/repo (see below).less -S, rather than in your IDE..vscode/tasks.json,.vscode/settings.json,.vscode/launch.json,.vscode/extensions.jsonpackage.jsonscripts:preinstall,install,postinstall,prepare- every
*.config.js,*.config.tsand*.config.mjs .git/hooks,.husky/,.devcontainer/,Makefile,setup.py,pyproject.tomlbuild hooks- AI-assistant config (
.claude/,.cursor/,CLAUDE.md,AGENTS.md, MCP config), which can contain hooks or instructions aimed at your coding agent
awk 'length > 300 { print FILENAME ":" FNR ": " length }' $(git ls-files)settings.json in VS Code, Cursor, Windsurf or any other fork:{
// Never run tasks automatically on folder open
"task.allowAutomaticTasks": "off",
// Keep Workspace Trust on, and open unknown folders in Restricted Mode
"security.workspace.trust.enabled": true,
"security.workspace.trust.untrustedFiles": "prompt"
}
Tip: When VS Code asks “Do you trust the authors of the files in this folder?”, the answer for any interview repo is No. Restricted Mode still lets you read the code. It just stops tasks, debuggers and many extensions from running it.
npm install --ignore-scripts (or the pnpm/yarn equivalent) closes one door. The October case shows it’s
not enough on its own: that attack never touched npm.Assume full compromise if one of these repos was opened and trusted in your IDE, or if its dependencies were installed. Act from a different, clean device.
.env files, API keys, cloud credentials, DB passwords, deploy
tokens and SSH keys (remove the old public keys from servers and GitHub too).pipx install devguard-scanner # or: uv tool install devguard-scanner
# Scan a GitHub repo WITHOUT cloning it: git never runs, so clone-time hooks can't fire,
# and the files never land in a folder your IDE could open
devguard scan https://github.com/owner/repo # add --ref BRANCH|TAG|SHA if needed
# Scan a local folder or an extracted zip
devguard scan path/to/repo
# Hosted API (public repos); Swagger UI at https://devguard-scanner.vercel.app/docs
curl -s 'https://devguard-scanner.vercel.app/v1/scans/github/owner/repo?format=md'
# Throwaway container
docker run --rm ghcr.io/yilmazhasan/devguard-scanner scan https://github.com/owner/repo --stdout md
blockreviewindicatorsno-indicatorsnpm install.1 when findings reach --fail-on (default high).No scanner can tell you a repo is safe, this one included.
no-indicators verdict means “nothing matched”, not “safe”. Use the scanner as one layer, together with
healthy suspicion, a hardened editor and a disposable environment.