Harden your dev environment against supply chain attacks, from inside Claude Code.
A one-time /harden command for Claude Code that detects your installed package managers, proposes security configurations, and writes them. Covers npm, pip, uv, bun, pnpm, yum, dnf, go, and cargo. Protects against dependency confusion, typosquatting, compromised maintainer accounts, and malicious install scripts.
Works on macOS, Linux, and Windows.
mkdir -p ~/.claude/commands
curl -o ~/.claude/commands/harden.md \
https://raw.githubusercontent.com/yonatan-genai/claude-code-supply-chain-harden/main/commands/harden.mdThen type /harden in any Claude Code session. No restart needed, even if you're mid-session. It runs once, writes your configs, and you're done. No ongoing hooks, no background processes.
- Detects your OS and installed package managers (npm, pnpm, bun, uv, pip, yum, dnf, go, cargo, brew)
- Checks for existing configs, CI pipelines, and lockfiles
- Shows you a numbered list of proposed changes with explanations
- You pick which ones to apply (all, some, or skip)
- Writes user-level configs (merges with existing, never overwrites)
- If CI is detected with unpinned deps, proposes project-level configs too
- Appends rules to
~/.claude/CLAUDE.mdso Claude itself follows the same guardrails
- Package age attacks — compromised account publishes malicious version, yanks it within hours. Blocked by requiring packages to be at least 7 days old before install (npm
min-release-age, uvexclude-newer). - Malicious install scripts — postinstall/preinstall running arbitrary code. Blocked by
ignore-scripts=truein npm. Python has no equivalent, but most packages ship as wheels (no setup.py execution), and age filtering is the main defense. - Dependency confusion —
--extra-index-urlchecks all indexes and picks highest version. Blocked by CLAUDE.md rules and uv's safe first-index default. - Unsigned packages — yum/dnf repos with
gpgcheckdisabled. Fixed by settinggpgcheck=1globally. - Claude using pip instead of uv — pip has no age filtering, no dependency confusion protection, almost nothing configurable for security. CLAUDE.md rules enforce uv usage.
- Insecure CI pipelines —
npm installinstead ofnpm ci, unpinned pip deps in workflows. Detected and fixed with project-level configs or workflow changes.
| Manager | Config file | What it sets |
|---|---|---|
| npm | ~/.npmrc |
min-release-age=7d, ignore-scripts=true, package-lock=true |
| uv | ~/.config/uv/uv.toml |
exclude-newer = "7 days" |
| bun | bunfig.toml |
minimumReleaseAge = 604800 (direct deps only) |
| pip | ~/.config/pip/pip.conf |
require-virtualenv = true (or install uv) |
| yum | /etc/yum.conf |
gpgcheck=1, sslverify=1 (requires sudo) |
| dnf | /etc/dnf/dnf.conf |
gpgcheck=1, sslverify=1 (requires sudo) |
| go | (none) | Secure by default. Checks for GONOSUMCHECK overrides. |
Windows paths differ (%APPDATA%\uv\uv.toml, %APPDATA%\pip\pip.ini, etc.) and are handled automatically.
| Situation | Change |
|---|---|
CI uses npm install instead of npm ci |
Recommend switching to npm ci, add project .npmrc |
CI uses pip install with unpinned versions |
Recommend uv with --exclude-newer, or pin versions |
Appended to ~/.claude/CLAUDE.md so Claude follows the same rules:
- Use
uvinstead ofpip/pip3(or use venvs if uv not available) - Never use
--extra-index-url(dependency confusion) - Never use
--trusted-host(disables TLS) - Never re-enable
ignore-scriptsglobally - Never use
--nogpgcheckor--setopt=gpgcheck=0 - Never pipe curl/wget to shell
- bun
minimumReleaseAgeonly covers direct deps, not transitive. - npm
min-release-agerequires npm >= 11.10.0 (Feb 2026). Older versions are told to upgrade. - yum/dnf changes require sudo. The skill shows the exact command and asks the user to run it.
- pip has almost no security features. The skill recommends uv. If declined, it sets
require-virtualenv=trueas a minimal safety net. - Python install scripts (setup.py) can't be disabled in pip or uv. Age filtering is the main defense.
MIT