Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

internetcondom

internetcondom

Protection against npm supply-chain attacks.
One command, three layers, no account.

License: GPL-3.0 POSIX sh No dependencies


curl -fsSL https://raw.githubusercontent.com/orlyjamie/internetcondom/main/install.sh | sh

Or read it first:

curl -fsSL -o install.sh https://raw.githubusercontent.com/orlyjamie/internetcondom/main/install.sh
less install.sh && sh install.sh

Why three layers

On 2026-08-04 the keyv and cacheable namespaces were compromised by pushing straight to main and cutting an immediate release, so the poisoned versions published with valid GitHub Actions provenance. Shai-Hulud spread to 868 packages across 1381 versions within hours, carrying a credential-stealing worm.

No single control would have stopped that. Each of these covers a different blind spot:

Layer Kind Stops Blind to
Socket Firewall reactive known-malicious packages, at the network anything newer than the feed
Minimum release age proactive everything published in the last N days a patient attacker
ignore-scripts structural the execution vector itself nothing — but it is not a resolution control

Socket flagged keyv@6.0.0 about six minutes after publication. Layer 2 covers that window. Layer 3 covers both: Shai-Hulud propagates through a preinstall hook, and a compromised package is inert until something runs on install.

What it actually does

  1. Installs sfw (Socket Firewall Free) to ~/.local/bin — no sudo, no account, no API key. Falls back to npm i -g sfw if the binary download fails.

  2. Wraps your package managers with shell functions so sfw applies without anyone remembering to type it: npm npx pnpm yarn pip pip3 uv cargo.

  3. Sets a minimum release age of 14 days, per manager, version-gated:

    Manager Key File Unit Needs
    npm min-release-age ~/.npmrc days npm 11.10.0+
    pnpm minimumReleaseAge ~/.config/pnpm/config.yaml minutes pnpm 10.16+
    yarn npmMinimalAgeGate via yarn config --home minutes Yarn 4.10.0+
    uv exclude-newer ~/.config/uv/uv.toml duration recent uv

    Units differ per manager. pip and cargo have no native equivalent.

  4. Sets ignore-scripts=true in ~/.npmrc.

Skips anything you do not have installed, and anything too old to support the setting, and says so. Skips are not failures.

Coverage

Ecosystem Screened by sfw Release age ignore-scripts
npm / pnpm / yarn
pip ✗ none exists
uv
cargo ✗ none exists
bun / deno ✗ not supported

JavaScript gets all three layers. Python and Rust get network screening, plus a cooldown on uv. ignore-scripts is npm-family only.

Staying current

sfw's detection is server-side, so an older binary is not a stale feed. Update it for fixes and new ecosystem support, not for detection coverage.

The installer pulls from releases/latest/download. To refresh in place:

sh install.sh --update

It updates sfw the same way it arrived — if npm installed it, --update uses npm i -g sfw@latest rather than dropping a binary that would silently shadow it.

Weekly, unattended:

# cron
0 9 * * 1 /path/to/install.sh --update >/dev/null 2>&1
# macOS launchd — ~/Library/LaunchAgents/com.internetcondom.update.plist
launchctl load ~/Library/LaunchAgents/com.internetcondom.update.plist

Re-running the whole script is always safe: it is idempotent, replaces its own marked block rather than appending a second copy, and backs up every file it touches once, to <file>.internetcondom.bak.

Package managers themselves are not auto-upgraded. The script reports which one is too old and what version it needs.

Per-repository

Machine-level config protects you. Committed config protects everyone who clones, plus CI. Both matter.

# pnpm-workspace.yaml
minimumReleaseAge: 20160        # 14 days, in minutes
minimumReleaseAgeExclude:
  - '@yourorg/*'
# .npmrc
ignore-scripts=true
min-release-age=14
# .yarnrc.yml
npmMinimalAgeGate: 20160

In CI and Docker, use the lockfile-respecting install and keep the flag explicit:

COPY .npmrc package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

If a dependency genuinely needs its install hook — ffmpeg-static, puppeteer and friends fetch binaries that way — allow it by name rather than switching the protection off wholesale:

npm rebuild ffmpeg-static

For coding agents

Add to AGENTS.md / CLAUDE.md:

## Dependencies
- Use pnpm. Never bypass the minimumReleaseAge setting in pnpm-workspace.yaml.
- Never pass --ignore-scripts=false, --no-strict-peer-dependencies, or edit
  .npmrc to weaken it.
- Adding a dependency requires asking first. Prefer node built-ins and packages
  already in package.json.
- `npm rebuild <pkg>` is the sanctioned way to run a needed install hook.

Instructions in a file are guidance an agent can miss. The shell wrapper is what enforces it.

Limitations

  • Shell functions are interactive-only. A #!/bin/sh script, a Makefile, or a Docker build invoking npm bypasses them. Commit the per-repo config for those.
  • bun and deno are not wrapped. Socket Firewall Free covers npm, yarn, pnpm, pip, uv and cargo. sfw passes unknown commands straight through, so wrapping bun would look like protection while providing none.
  • ignore-scripts breaks packages that need install hooks. By design. Use npm rebuild <pkg>.
  • A 14-day window is not a proof. It raises the cost and buys detection time. A sufficiently patient attacker waits it out.
  • command npm ... bypasses everything. Deliberate. A guard that breaks real work gets deleted rather than fixed.
  • sfw is a closed-source binary under PolyForm Shield. Skip layer 1 if that is not an acceptable trade — the layers are independent.

Uninstall

sh install.sh --uninstall

Removes the shell block and the ~/.npmrc keys it added, leaving everything else in those files untouched. sfw itself and the pnpm/yarn settings are left alone — delete them by hand if you want them gone.

License

GPL-3.0-or-later. Copyright (C) 2026 Jamieson O'Reilly. See LICENSE.

About

Protection against npm supply-chain attacks. One command: Socket Firewall on every package manager, minimum release age, ignore-scripts.

Topics

Resources

Stars

12 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages