That LinkedIn Job Offer Hid a Backdoor in npm install A developer received a LinkedIn message from a recruiter at a crypto startup asking to review a GitHub repository before a technical interview. The repository contained a backdoor in npm's prepare script that executed on npm install, part of a North Korean state-sponsored campaign tracked as Sapphire Sleet. The attack has spread 1,700 malicious packages across multiple ecosystems since December 2022. A developer received a LinkedIn message last week from a recruiter at a crypto startup. Normal enough. The ask: review a GitHub repository before the technical interview — “just check for deprecated Node modules.” The developer opened the repo. Nothing obvious jumped out. Then, before running npm install , they passed the repo to a read-only AI agent for a first look. The AI found it immediately. Buried in app/test/index.js — disguised as 250 lines of test boilerplate — was a backdoor. The moment npm install ran, it would execute. No test command needed. Just install. The payload assembled a URL from string fragments, phoned home to an attacker’s server, and ran whatever code came back. The developer, Roman Imankulov, published the full account today https://roman.pt/posts/linkedin-backdoor/ — it hit 629 points on Hacker News within hours. The Mechanism: What prepare Actually Does Most developers know to be careful about running npm install on random packages. Almost nobody audits the root package.json before installing an unfamiliar repo. That’s the gap attackers exploit. npm’s prepare lifecycle script runs automatically on every npm install . No flags, no confirmation. The malicious package.json in Imankulov’s case looked like this: { "scripts": { "prepare": "node app/index.js", "app:pre": "node app/test/index.js" } } That’s it. npm install executes node app/index.js , which loads the test file, which assembles the C2 URL, which runs the second-stage payload. The attack is buried three files deep — none of which look alarming in isolation — and triggered by the most routine command in Node.js development. A second developer described a nearly identical scenario on DEV Community https://dev.to/vladimirnovick/a-linkedin-recruiter-sent-me-malware-disguised-as-a-pre-interview-code-review-2k3j , with a more sophisticated variant: the C2 endpoint was hidden inside a public Google Doc, letting the attacker rotate the destination server without touching the repository. It used new Function.constructor "require", code instead of eval to evade static analysis tools. The payload targeted environment variables — API keys, AWS credentials, tokens — everything a developer has loaded in their shell. Why It’s Convincing The repository in Imankulov’s case had 39 commits, all attributed to a real full-stack developer who confirmed he’d never worked on the project. The recruiter profile belonged to a real arts journalist, impersonated with technically-worded messages. When Imankulov suggested reading the code before installing, the recruiter pushed back — specifically steering him toward npm install . This isn’t phishing. It’s social engineering with operational precision. The Industrial Scale Behind It Microsoft tracks this campaign as Sapphire Sleet — a North Korean state-sponsored threat actor https://www.microsoft.com/en-us/security/blog/2026/04/16/dissecting-sapphire-sleets-macos-intrusion-from-lure-to-compromise/ also known as Contagious Interview, active since December 2022. In April 2026 alone, the operation spread 1,700 malicious packages across npm, PyPI, Go, and Rust. In March 2026, Axios itself was compromised — versions 1.14.1 and 0.30.4 delivered a cross-platform RAT to developers who had nothing to do with any job interview. They just used a popular library. The LinkedIn recruitment variant is one branch of the same tree. Individual developer targeting, package ecosystem poisoning, maintainer account compromise — all converging on the same goal: get into a developer’s machine, exfiltrate credentials, establish persistence. What to Do Right Now The most effective immediate action: use npm install --ignore-scripts when reviewing unfamiliar repositories. This prevents all lifecycle scripts — prepare , postinstall , preinstall — from running. Make it permanent: npm config set ignore-scripts true Before installing anything from an unknown source, open package.json and check the scripts field. Any entry running a file from the project’s own source tree — especially under prepare or postinstall — is worth tracing before you touch install. For repos from unknown sources, use a throwaway environment: a Docker container, a VM, or a remote VPS. The attack only executes locally. Reading code on GitHub is safe. The longer fix is arriving. npm v12, shipping in July 2026 https://github.blog/changelog/2026-06-09-upcoming-breaking-changes-for-npm-v12/ , flips allowScripts to false by default. Lifecycle scripts will require explicit approval via npm approve-scripts . We’ve covered what npm v12 breaks and how to prepare https://byteiota.com/npm-v12-breaking-changes-what-breaks-in-july-2026/ — the recruiter backdoor is exactly the attack this change is designed to stop. Until July, the rule is simple: any LinkedIn recruiter asking you to clone and install a repo before a technical interview should be treated as untrusted input. Read the package.json first. Run in a sandbox. Ask why they’re specifically pushing npm install . The answer is usually in that prepare script.