Skip to content

Releases

snare 1.9.0 — update restarts the guard, notifies or auto-installs

Choose a tag to compare

@AviOfLagos AviOfLagos released this 07 Nov 12:05
f4747ea

snare update now restarts the guard and cleans up after itself. And snare tells you when there's a new version, or installs it for you.

No more snare guard stop && snare guard start

After an update, the background guard used to keep running the old version until you restarted it by hand. snare update now restarts it on the new code. It also catches a guard that is still on an older version even when there's nothing new to download. To do it yourself any time: snare guard restart.

Old leftovers are cleared

An update now removes what the previous version left behind:

  • the gate's cached verdicts, which only the old version could use;
  • blocks waiting in snare respond for repositories you've since deleted;
  • the oldest part of any log past 1 MB.

Your backups, reports and evidence are never touched.

Told when there's a new version, or updated automatically

Choose how snare keeps itself current:

snare update --mode notify   # the default: tells you when a new version is out
snare update --mode auto     # installs new versions itself, then tells you what changed
snare update --mode off      # never checks
  • notify checks in the background, at most every six hours, and shows one line: snare 1.9.1 is out (you have 1.9.0) — update: snare update.
  • auto only moves forward along main and never touches an install you've edited. It logs to ~/.snare/logs/auto-update.log.
  • The check now also runs when a coding agent is using snare. Before, it only ran in a terminal, so installs used mostly through agents never found out about new versions.

Update

snare update && snare selftest

This one time, the update runs on your current version, which doesn't know how to restart the guard yet. So restart it yourself once: snare guard stop && snare guard start. From 1.9.0 on, snare update does it for you.

136 self-test checks pass.

snare 1.8.0 — a block explains what it caught

Choose a tag to compare

@AviOfLagos AviOfLagos released this 06 Nov 17:23
af9a192

When snare blocks something, it now tells you exactly what it caught, and gives it to you in a form you can copy.

What snare caught, up front

A block now opens with each file and line snare suspects, why, and the text that matched. The whole message is also saved to ~/.snare/logs/last-block.txt. Print it again any time:

snare gate report

Paste it into your own agent, an issue or a chat to work out what it is. An agent's transcript scrolls away; the report stays.

Read it yourself before you allow it

A block can be a false alarm: a minified file, an unusual config. If you think it is one, the message now says what to do first:

  1. Open every flagged file and read it in full, not just the flagged line.
  2. Check who added it and when: git log -p -- <file>.
  3. Only then, in your own terminal, run the snare gate allow … command the block prints.

An agent can help you understand the code. But an agent reading a poisoned repository can be talked into calling it safe, so the decision has to rest on what you read.

Not sure, or it looks real? snare respond takes charge of the clean-up.

For coding agents

The instructions snare agents install writes now tell agents to show you the whole block message, not a summary. Run snare agents install again to refresh them.

Update

snare update && snare selftest

132 self-test checks pass.

snare 1.7.1 — the 'behind' message goes away after you update

Choose a tag to compare

@AviOfLagos AviOfLagos released this 06 Nov 13:50
a1d3824

The "commit(s) behind" message now goes away after you update.

snare remembers whether it's behind so it doesn't need to ask GitHub on every command. But it never updated that memory when you updated. Right after snare update succeeded, every command still said "1 commit(s) behind, run: snare update". The memory refreshed only once a day, and only in an interactive terminal. Under a coding agent it never refreshed at all. One install showed a "behind" from 19 days and three releases ago.

Now the memory is tied to the exact commit it describes. As soon as your install changes, it's ignored, whether that's through snare update, a git pull or a reinstall. snare update records the result it just reached.

Together with 1.7.0, which makes snare update always update from main, this fixes "snare says it's up to date but I'm stuck" and "snare says I'm behind but update does nothing".

Update

snare update && snare selftest

On a version before 1.7.0 and stuck? Run this once:

cd ~/snare && git checkout main && snare update

131 self-test checks pass.

snare 1.7.0 — snare update now actually updates

Choose a tag to compare

@AviOfLagos AviOfLagos released this 06 Nov 13:36
030e35e

snare update now actually updates.

Some of you saw snare update answer "already up to date" every time while snare version said you were behind. Both were telling the truth about different branches. snare update pulled whatever branch your install was on, and snare version compared against main. If your install was ever left on another branch, it never moved again.

Updates come from main, always

  • snare update now moves your install to main, where releases are published, and fast-forwards it.
  • If your install is on a branch with work that isn't on main, snare leaves it alone. It prints the one command to switch.
  • snare update --check and the "behind" notice measure against main too, so all three agree.

Stuck on an older version? That version still has the bug, so run this once:

cd ~/snare && git checkout main && snare update

Linux: no more re-downloading the malware list on every command

On Linux, snare couldn't read how old its malware list was, so it treated the list as stale and downloaded it again, 2.3 MB at a time, on every agent command (at most once every ten minutes). It now reads the age correctly on Linux and macOS.

snare no longer trips its own gate

The website's "hidden payload" demo carried the campaign's markers verbatim. So anyone cloning or pulling snare under the agent gate got stopped with "fire on the mountain", and the only way through was to approve the block without reading it. Training people to do that is the opposite of what the gate is for.

The demo is now stored reversed and restored when the page loads. It looks the same on the site, but the file carries no live marker. snare still checks its own branches and pulls like anyone else's. A new self-test checks the website file the way a fresh clone would see it.

What only the owner can do (#54)

Some branches were never real work, just a delivery vehicle for the payload. When snare fix <owner/repo> cleans one of these and finds it adds nothing to the default branch, it now says so under What only you can do. That section gives you the exact delete command, links the branches page, and says when forks still hold the old history.

snare still never deletes a repository, an organisation or a remote branch itself. The backup bundle it makes before every fix is your way back.

Update

snare update && snare selftest

130 self-test checks pass.

snare 1.6.0 — known-malicious packages in every ecosystem

Choose a tag to compare

@AviOfLagos AviOfLagos released this 25 Oct 13:15
de8f49f

snare now knows which package versions are malware, for npm, Python, Rust, Go and more, and stops them before they install.

Supply-chain malware isn't only an npm problem anymore. This month, LiteLLM's release pipeline was hijacked, and version 1.107.0 on PyPI shipped a file that Python runs every time it starts. In May, the TrapDoor campaign hit npm, PyPI and crates.io at once. Until now, snare didn't read any of those ecosystems.

Stopped before it installs

When a coding agent, or you, runs an install that names a known-malicious version, the gate stops it and shows the advisory:

🔥 FIRE ON THE MOUNTAIN — snare stopped this before it ran:
    pip install litellm==1.107.0

  litellm@1.107.0 (pypi) is known malware — this version: https://osv.dev/vulnerability/MAL-…
  • Install commands covered: npm, pnpm, yarn, bun, npx, pip, uv, pipx, poetry, pdm, cargo, go, gem and composer.
  • Files covered: requirements files and lockfiles are checked too.
  • No version given: for a package where only some versions are bad, snare asks the registry which version would install. That's the same request the install was about to make. It only stops the install if that version is on the list.

Find and fix what's already there

snare deps            # this project: lockfiles, node_modules, virtualenvs
snare deps --system   # also your global Python, pipx, npm and cargo installs
snare deps fix        # remove each one, or replace it with a version that isn't listed

snare deps fix asks about each package. Replacements install with scripts turned off, so they can't run code while installing. If something malicious was actually installed, snare tells you to rotate your credentials next, since stealing them is what these packages are for.

Files other languages run on their own

The gate already watched package.json scripts and build configs. It now also checks:

  • setup.py, conftest.py and build.rs;
  • sitecustomize.py and .pth files, which Python runs at every start, the LiteLLM trick;
  • //go:generate lines.

It flags them when they download code, or decode and run it. Ordinary ones are left alone.

Private by design

The known-malware list is built every six hours from OpenSSF's malicious-packages database, about 117,000 packages. Every snare downloads the same file and checks against it on your machine. Nothing about your packages is sent anywhere.

Also in this release

  • A false alarm on incoming code can now be approved. Before, if the gate stopped a git checkout, pull or clone, snare gate allow only looked at files on disk. It said "nothing to allow" while the gate kept blocking. Now allow also looks at the code that's on its way in, and the block prints the exact command to approve it.
  • snare respond handles those blocks too. It re-checks them, and lets you allow or leave each one.

Upgrade

snare update

Then check: snare deps status and snare deps.

Known-malware list (rebuilt every 6 hours)

Choose a tag to compare

@github-actions github-actions released this 25 Oct 13:14
de8f49f

Machine-readable list snare downloads. Built from github.com/ossf/malicious-packages. Not a snare release.

snare 1.5.0 — the gate: scan before code comes in or runs

Choose a tag to compare

@AviOfLagos AviOfLagos released this 14 Oct 22:51
12538c3

snare now checks code before your coding agent pulls it in or runs it, and shows you what it found.

The incident behind this release was ordinary work: a pull, an install, npm run dev. A coding agent did it in a repository that had been poisoned upstream, and nobody found out for days. snare could have caught it. Nothing ran snare at that moment.

The gate

Before a clone, pull, merge, checkout, install or npm run, snare checks the code that command is about to bring in or run. If it's clean, the command goes ahead, adding about 0.4s; everyday commands like git status and ls add about 30ms. If it isn't clean, the command doesn't run and you see this:

🔥 FIRE ON THE MOUNTAIN — snare stopped this before it ran:
    npm run dev

  /path/to/repo carries a supply-chain payload:
  package.json:1 — "dev" runs api.js first, and api.js is obfuscated: one line of 29013 characters
      ↳ node api.js && next dev

Every finding shows the file, the line, what snare suspects and the code itself. It can be a false alarm: a minified file or an unusual config can look suspicious. So you decide:

  • It's mine and harmless: snare gate allow '<repo>' asks about each finding. An approval is tied to the file's exact content, so if the file changes it's flagged again.
  • Let snare take charge: snare respond.

Only the person at the keyboard can make either choice. A coding agent is refused both, and it can't turn the gate off.

Every coding agent gets it

snare asks before turning this on. When you install or update snare, it shows exactly which files it would change and asks. If you say yes, it adds the gate to Claude Code as a hook that runs automatically, and writes the same instruction into CLAUDE.md, AGENTS.md, ~/.codex/AGENTS.md and ~/.gemini/GEMINI.md, for each tool you have installed. Say no and nothing is changed, and you won't be asked again; snare agents install turns it on later. Nothing is installed when no one is at a terminal, or when a coding agent is the one running snare. snare agents status shows what's installed; snare agents uninstall restores your original files exactly.

snare respond acts on what it finds

  • It starts with what the gate stopped, checked again now. For each one you choose clean (backed up and staged for your review, never committed or pushed), allow, or leave.
  • If nothing turns out to be real, it offers to stop there instead of walking you through rotating every credential.
  • A finished run starts a fresh check. Before, it replayed an old summary ("infected repos found: 2") without naming the repos or doing anything.

snare never deletes a repository or an organization

This is now enforced, not just true of today's code. Every GitHub and git call snare makes goes through one guard. It refuses repository and organization deletion, archiving and transfer, any API DELETE, and any push that removes remote branches. The selftest checks this, and fails if any code tries to get around the guard.

Also

  • Husky is no longer reported as malware. A husky hook that downloads and runs code still is.
  • The shell shield no longer breaks npm for coding agents.
  • snare update refreshes the shield and the agent setup in place.

Known limits

  • The automatic hook is Claude Code only. Codex, Cursor and Gemini get the written instruction, which they can ignore.
  • npm install <package> runs that package's own install scripts. The gate checks the repository you are in, not the package you are adding.
  • node_modules is left to snare scan repo.

Upgrade

snare update

Then check: snare agents status and snare doctor.

Full detail, including every bypass found and closed during seven review rounds, is in CHANGELOG.md.

v1.4.3 — a purge that reported zero and left the payload

Choose a tag to compare

@AviOfLagos AviOfLagos released this 13 Oct 20:46
5918654

Found by purging a real repository and then scanning what came back.

A 29,057-byte api.js survived the rewrite, and the purge printed blobs still carrying a hidden payload: 0. The verify step re-runs the same cleaner, so anything the cleaner cannot see verifies clean — a false clean in remediation, reported with a number beside it.

Why it was invisible

The file opened with the whitespace wall. 424 tabs, then 28KB of code on the same line, and that was the whole file. One rule needs real code in front of the run; the other needs the payload to look obfuscated. This satisfied neither.

The obfuscation style was unrecognised — no _0x identifiers, no \u00 escapes, no eval(, no atob(. Just long random identifiers (RvJq_qacMrKUHEOocOXlFJqDe) and an array of hex strings decoded at runtime.

What changed

  • A line starting with 50+ spaces or tabs, long, dense, carrying a hard campaign marker is dropped on that basis alone. The whitespace prefix is the structural tell, and no honest file opens that way.
  • Two adjacent 8+ character hex strings inside an array literal is now an obfuscation signal of its own.

Verified on the live sample: cleans to 0 bytes. Controls untouched — snare's own guard pattern, a minified vendor bundle, deeply indented source, a JSON document, a tab-indented recipe.

If you have run --purge-history before, run it again with this version. A clean report from an older one did not mean the history was clean.

snare update && snare fix <owner/repo> --purge-history --push

v1.4.2 — four false positives out, four real ways in

Choose a tag to compare

@AviOfLagos AviOfLagos released this 13 Oct 00:42
23495a8

Found by running 1.4.1 against a real repository rather than a fixture.

The false positive

node\s+.*(-e|--eval) left the flag unanchored, so atlas-engine matched. An honest PostToolUse hook running packages/atlas-engine/hooks/atlas-tag.ts was reported as "an agent hook runs a dropper, on its own, every session" — on the owner's own repository, by a check shipped hours earlier. The same pattern sat in the package.json install-hook check and the API scan.

The half nobody had noticed

Reviewing that fix turned up the other side. node -p 'require("child_process")' evaluates its argument exactly as -e does, --print is its long form, and -pe / -ep are how you write it without it looking like either. None of those four were caught — not by the old pattern, not by the corrected one.

Measured, sixteen commands

old new
honest commands flagged 4 0
evaluating forms caught 6 of 10 10 of 10

A detector that cries wolf on a project's own tooling is how people learn to ignore it, so both halves have regression tests and the selftest asserts each flag separately rather than the one that was easy to remember.

Known limitation

Shell word-splitting tricks (node\${IFS}-e) still evade the pattern. The structural checks — an obfuscated target file, the IOC strings — are what catch those.

snare update

v1.4.1 — update no longer steals the launcher

Choose a tag to compare

@AviOfLagos AviOfLagos released this 13 Oct 00:31
4816ccb

snare update relinked ~/.local/bin/snare unconditionally, so running it from any checkout — a fork, a git worktree, a throwaway clone — silently pointed the global launcher at that checkout. Delete the clone afterwards and snare is a dangling symlink, with nothing having said so.

Found by doing it, while testing the 1.4.0 remote repointing from a clone in $TMPDIR.

the launcher points at… before after
this checkout relinked, announced silent, unchanged
a different, working install silently stolen left alone and reported
nothing (broken) relinked relinked — any working snare is an improvement
anything, with --relink n/a relinked on request

The case this existed for still works: move your install and the launcher is left dangling, which is the repair case.

Five regression tests, all driven through SNARE_BIN in a temp directory — a test that relinks the tester's own launcher is the bug itself.

snare update