A fake recruiter pushed a Python developer toward a poisoned JavaScript repo, and an AI code review flagged the trap before npm could run it.

Python developer Roman Imankulov caught a malicious GitHub repo before it could compromise his machine, after a fake recruiter steered him toward broken proof-of-concept code during a LinkedIn job pitch.
The approach followed a pattern security teams now see across developer communities: an attacker poses as a recruiter, sends a coding task, and waits for the target to run a routine install command. In this case, Imankulov used a rented Hetzner VPS and asked an AI coding agent running Codex to inspect the code in read-only mode.
The agent flagged app/test/index.js. Imankulov had skimmed the same file and saw sloppy test code. The agent saw a server URL split into fragments and a network request that would execute whatever the server returned.
The repo also used a prepare hook in package.json. A developer who ran npm install would trigger the script before reviewing the project. That hook gave the attacker a path from a job interview into a developer workstation.
That workstation often holds SSH keys, cloud tokens, package registry credentials, and access to private repositories. A single install command can give an attacker a bridge into company code, build systems, and production infrastructure.
Devashri Datta, an independent open source and security architect, told The Register that the attacker relied on a normal developer habit rather than a suspicious binary. Developers run npm install to start most JavaScript projects. The attacker hid execution inside npm’s lifecycle system and split the malicious URL to avoid basic scans for known indicators.
Imankulov also checked the repo’s apparent author. The commits looked tied to a developer with a public work history, but the developer told him someone had impersonated him on GitHub before. The LinkedIn recruiter profile also appeared to borrow details from a real arts journalist. Imankulov said the person behind the profile showed more technical knowledge than the profile suggested.
LinkedIn’s own fraud numbers show the scale of that problem. The company restricted 386,000 accounts after user reports from January through June 2025, up from 266,000 in the previous six-month period and 86,000 from January through June 2021.
Attackers have used fake interviews and job offers to target developers for years. North Korean-linked groups have run similar campaigns against software workers, with the goal of stealing credentials, source code, and access to internal systems.
The incident also shows a narrow, useful role for AI in security work. Imankulov did not ask the agent to run the repo or fix it. He used it as a reviewer inside a constrained environment before execution. That choice mattered because the dangerous code lived in a place a human reviewer might dismiss as messy test scaffolding.
GitHub plans to change npm’s default script behavior in npm 12. The new behavior will require projects to allow dependency install scripts before npm runs them. GitHub product manager Leo Balter said install-time lifecycle scripts create the largest code execution surface in the npm ecosystem because one compromised transitive dependency can run code on a developer machine or CI runner.
Imankulov said he switched to pnpm for personal safety because pnpm does not run those scripts by default in the same way. Teams can also reduce risk with isolated developer containers, cloud workstations, short-lived credentials, and rules that force engineers to inspect untrusted code outside their main environment.
For companies, the lesson reaches beyond endpoint antivirus and repository scanning. Attackers now target the moment before code enters a company’s supply path: the developer’s first contact with a repo. Security teams need controls at that point, including sandboxed evaluation environments, package manager policies, secret isolation, and review steps for code from job candidates, contractors, vendors, and unknown recruiters.

Comments
Please log in or register to join the discussion