securityAIbuilding

Someone tried to social engineer me via LinkedIn. My AI agent caught it.

A recruiter DM, a GitHub repo, and a backdoor hiding in 300 lines of fake test comments.

· 4 min read

A few weeks ago I got a LinkedIn message from someone asking for help reviewing a project. Normal enough - I get these occasionally. The pitch was that they were building a Node.js service, had hit some performance issues, and wanted a second set of eyes on the codebase before a client demo.

I looked them up. Real profile, reasonable connection count, a GitHub with a few repos that looked like actual work - not the usual two-file placeholder accounts. The repo they shared had commits spread over months, a proper README, CI setup. It looked legitimate.

I almost just cloned it.

What stopped me

I’ve been running an AI agent - OpenClaw at the time - that I use for most of my server-side work. Before pulling anything down locally, I had it do a quick pass on the repo first. Read the files, check for anything unusual.

It came back with this:

“there’s a backdoor in app/test/index.js. it downloads code from a remote server and runs eval() on it when you do npm start.”

I opened the file. There it was - two lines of actual malicious code, buried inside roughly 300 lines of fake test comments. The kind of thing your eyes slide right past when you’re skimming.

How it was built to evade you

The more I looked, the more deliberate the construction was.

The setup script had environment checks that specifically blocked execution inside VSCode terminals and cloud IDEs like Gitpod or Codespaces. If you tried to run it in either, it would throw a vague dependency error and exit. The only way to get it “working” was to run it on your actual machine, in a regular terminal.

That’s the point. On your local machine, a script running under your user has access to:

  • Your SSH keys (~/.ssh/)
  • Your .env files and any credentials in your home directory
  • Active browser sessions via the profile directory
  • Any tokens stored in shell config

The two malicious lines would phone home, pull down whatever payload the attacker wanted to run that day, and execute it in your current session. The actual attack code isn’t even in the repo - it lives on their server, swappable at any time, invisible to any static analysis of the repository itself.

The social engineering part

What made this work - or almost work - was the effort put into the cover story. Most malicious repos are obvious: freshly created, sparse commits, no real activity. This one had history. The GitHub profile had stars, followers, other repos with issues and PRs.

The LinkedIn message was also calibrated. Not “hey can you run this and tell me if it works” - that would be a red flag. Instead: “I’m prepping for a client demo and want a code review from someone technical.” That framing makes you think you’re doing a favour, not running untrusted code.

It’s designed to exploit the thing that makes developers good at their jobs: the reflex to just run the thing and see what happens.

What I’d do differently

Nothing, as it turns out - having the agent read the code before touching it locally is now just how I handle unsolicited repos. But if you don’t have that habit yet, a few things that would have caught this:

  1. Open the file tree before cloning. Look at what’s actually in there, not just the README. Test directories with unusually large files are worth a look.
  2. Search for eval(, exec(, child_process, and any URLs before running anything. Takes thirty seconds.
  3. Use a VM or container for any code you didn’t write. Obvious in hindsight, rarely done in practice.

The agent caught it in seconds. Not because it was doing anything clever - just reading code without any of the social context that was designed to make me trust the source.

That’s the part worth keeping in mind. The attack wasn’t technical. The technical part was trivial - two lines of JavaScript anyone could write. The attack was the LinkedIn profile, the plausible GitHub history, the reasonable-sounding request. Everything that made me want to help.

The code was almost the afterthought.

← All posts