A backdoor in a LinkedIn job offer

lwhsiao2 pts0 comments

A backdoor in a LinkedIn job offer - Roman Imankulov<br>Roman Imankulov<br>Full-stack Python developer. Building Smello.

search results (esc to close)

15<br>Jun 2026

A backdoor in a LinkedIn job offer

table of contents

Last week, I got a LinkedIn message from a recruiter at a small crypto startup. We exchanged a few messages over a couple of days, she described a broken proof-of-concept they needed a lead engineer for, and then sent me a public GitHub repo to review. Specifically, she asked me to &ldquo;check out the deprecated Node modules issue.&rdquo;<br>It&rsquo;s not uncommon to ask for a review of an existing codebase, but something felt off and raised an alarm in my head, so I decided to get a bit extra paranoid.<br>Instead of cloning and installing dependencies, I spun up a throwaway VPS on Hetzner, cloned the repo there, and pointed Pi at it in read-only mode, with only file-reading tools enabled:<br>pi --tools read,grep,find,ls

I asked the agent to review the codebase and flag anything suspicious. It stopped almost immediately at app/test/index.js.<br>The backdoor<br>The repo felt like a React frontend with a Node backend. The trap was in app/test/index.js, about 250 lines disguised as a test suite. Inside, a URL is assembled from fragments:<br>const protocol = "https",<br>domain = "store",<br>separator = "://",<br>path = "/icons/",<br>token = "77",<br>subdomain = "rest-icon-handler",<br>bearrtoken = "logo";

These combine into https://rest-icon-handler.store/icons/77.<br>Then, buried between walls of commented-out tests, the payload runs anything the server sends back to your machine.<br>The payload on line 225, hiding in plain sight between commented-out tests.<br>How it triggers<br>The file doesn&rsquo;t wait for the tests to run. app/index.js itself executes const test = require('./test'), which loads and runs app/test/index.js.<br>package.json wires app/index.js into startup:<br>prepare runs app:pre, which is node app/index.js.<br>The prepare script is the important one. npm runs prepare automatically after npm install, so just installing dependencies executes the backdoor.<br>The instruction to &ldquo;check out the deprecated Node modules issue&rdquo; was bait to get me to run npm install.<br>I could have let the payload run in the sandbox and watched what the server sent back as the second stage, but I stopped there. A repo that runs whatever a server hands it was enough evidence.<br>A borrowed identity<br>The commits in the repo were authored under the name and email of a real developer, a full-stack engineer with an ordinary LinkedIn profile, a personal website, and a GitHub account with a long history. I messaged him, pretending I&rsquo;d inherited the codebase and had a few implementation questions, to see how he&rsquo;d react. He told me he&rsquo;d never worked for them. He&rsquo;d been impersonated on GitHub before and had a repo taken down over it, and he had nothing to do with this one. He was reporting these repos too.<br>The whole commit history, 39 commits, attributed to one developer who&rsquo;d never touched the repo.<br>A second borrowed identity<br>The recruiter&rsquo;s profile belonged to a real arts journalist, a well-known one I looked up later, with a long cultural background and nothing technical on it. When I played along and told her I couldn&rsquo;t get the project to install, the journalist instantly turned into an expert on npm and Node versions. It was the same trick as the commits, another real person&rsquo;s identity borrowed.<br>The non-technical recruiter, suddenly debating Node versions and pushing me to run npm install.<br>This can happen to anyone<br>I&rsquo;ve heard of these attacks and read about them on HN, but when one came after me it still caught me a bit off guard. I suspected something from the first few messages, but on a more tired or rushed day, I could easily have run npm install before thinking it through. So, if you get a LinkedIn message asking you to review a repo, a bit of paranoia and good security hygiene never hurts.<br>Another takeaway is that reviewing the code with a read-only agent turned out more productive than reading it myself. The backdoor was dressed up as sloppy beginner code, but the agent flagged it in seconds.<br>I reported the repo to GitHub and the recruiter to LinkedIn. So far nothing has changed and the code is still up.

Security

Hey, I am Roman<br>I am a full-stack Python developer. Currently building Smello, a local-first HTTP traffic inspector for Python.<br>More about me

rsquo repo linkedin backdoor node test

Related Articles