A git repository can run code on your machine before you've decided to run anything. On September 29 a fake client sent us a project archive and asked us to check out a branch called "NDA", and a hook inside it would have downloaded and run a script the moment we did (the full story is here). We caught it because we looked first. This is the ten-minute triage we now run on every repository that arrives from someone we haven't worked with, with the exact commands, so you can run it too.
The principle behind every step: read the project as text before you let any tool act on it. Git, your editor and your package manager all execute things on your behalf. Until you know what they would execute, don't give them the chance.
Where code can run before you run it
Most people know that npm install runs scripts. Fewer know how many other places a repository can hide something that fires on its own. Here's the list we check, and whether each one survives a normal clone:
| Location | When it fires | Carried by git clone? |
|---|---|---|
.git/hooks/* | On checkout, commit, merge, rebase | No, only in an archive of the folder |
.git/config (core.hooksPath, core.fsmonitor, filters) | On many everyday git commands | No, only in an archive |
.githooks/, .husky/ | After a setup script points git at them | Yes |
.vscode/tasks.json with runOn: folderOpen | When you open and trust the folder | Yes |
package.json preinstall / postinstall | On npm install | Yes |
.envrc (direnv) | When you cd into the folder, once allowed | Yes |
Makefile, setup.sh, "run the demo" | When you run them | Yes |
Read the third column carefully. A fresh git clone from a hosting service never brings .git/hooks or .git/config with it, which is why the lure we received arrived as a .tar.gz of the whole folder. An archive of a repository is more dangerous than a link to one, and it's a fair question to ask why a client can't just send a link.
Step 1: list the archive, don't extract it
Listing an archive reads its table of contents. Nothing inside runs.
For a tarball: tar -tzvf project.tar.gz | grep -E '\.git/(hooks|config)'
For a zip: unzip -l project.zip | grep -E '\.git/(hooks|config)'
A normal repository shows a set of files ending in .sample, and those are inert. Any hook that isn't a .sample file is a stop sign. In our case the listing showed an executable post-checkout sitting among the samples, dated two weeks before the repository itself was created. That's all it took.
Also look at the owner names and dates in the verbose listing. Ours was packed by a user account with a different name from the sender, which is not proof of anything, but it's one more question.
Step 2: read git's own files as plain text
You can print a single file from inside an archive to your terminal without extracting it anywhere:
tar -xzOf project.tar.gz project/.git/hooks/post-checkout
tar -xzOf project.tar.gz project/.git/config
In a hook, look for anything that downloads or executes: curl, wget, base64, chmod +x, Invoke-WebRequest, iwr, mshta, or a URL ending in vercel.app or another free hosting domain. The FBI's September 2026 alert on this campaign lists several of the same strings as warning signs.
In .git/config, look for hooksPath, fsmonitor, sshCommand, and any [filter or [diff section with a command in it. A plain repository config has a handful of core settings and maybe a remote. Anything that names a program to run deserves a hard look, because git will run it for you during commands as ordinary as git status.
Step 3: check the files that run on open or install
If the archive passes the first two steps, it's reasonable to extract it (into a folder you don't open in your editor yet) and search it:
grep -rnE 'postinstall|preinstall|folderOpen|curl |wget |base64|chmod \+x|vercel\.app' . --include='*.json' --include='*.sh' --include='*.js' --include='Makefile'
Then read these by eye, because a grep only finds what you thought to look for:
package.json, thescriptsblock in particular.vscode/tasks.jsonand.vscode/settings.json- anything in
.githooks/,.husky/or ascripts/folder - the README's setup instructions (they tell you what they want you to run)
One more editor-specific note: when VS Code asks whether you trust the authors of a folder, "No" is the right answer for anything from a stranger. Restricted mode stops tasks and many extensions from running automatically.
Step 4: read documents without checking out branches
Often the whole point of the repository is to hand you a document, as ours was with its NDA. You don't need to switch branches to read it. Git can print any file from any branch straight from its object store:
git --git-dir=project/.git ls-tree -r NDA lists what's on the branch.
git --git-dir=project/.git cat-file -p <hash> > nda.docx writes one file out.
Neither command triggers a checkout hook. If you must switch branches, disable hooks for that one command: git -c core.hooksPath=/dev/null -c core.fsmonitor=false checkout NDA. That points git at an empty hooks location and turns off the file-system monitor, so nothing in .git/hooks or the monitor setting can fire.
When to stop and use a throwaway machine
Everything above is about reading safely. The moment you need to run a stranger's project (install dependencies, start the demo, run tests) do it in a disposable virtual machine or cloud box that holds none of your credentials: no SSH keys, no browser logged into client systems, no cloud tokens. The IC3 alert gives the same advice for unknown code.
Our rule of thumb for agencies, where one developer's laptop can hold keys to a dozen client systems:
| Situation | What we do |
|---|---|
| Hosted repo link from a known client | Clone and review normally |
| Archive of a repo from anyone new | Steps 1 to 4, never open in an editor first |
| Anything we're asked to install or run | Throwaway VM only |
| An NDA or contract "in the repo" | Ask for a PDF or e-signature link instead |
This takes about ten minutes the first time and two once it's habit. We think it's the cheapest security measure an agency can adopt, and it would have been enough on its own to stop the attack we received. If you want help building it into how your team onboards new clients, our cybersecurity team can set it up with you, and for the lead-qualification side of the same problem, see what we look for when vetting a development partner.
Sources
- Git documentation: githooks
- Git documentation: git-config (core.hooksPath, core.fsmonitor)
- VS Code documentation: tasks and running a task on folder open
- VS Code documentation: Workspace Trust
- npm documentation: scripts and lifecycle hooks
- FBI IC3 and partners: North Korean "WaterPlum" (Contagious Interview) alert, Sept 18, 2026
- OpenSourceMalware: DPRK hides malware in git hooks