depcurfew
One supply-chain security policy for npm, pnpm, Yarn, Bun, Deno, uv, pip, Poetry, PDM, Pipenv, Composer, Bundler, Cargo, Renovate and Dependabot, and a doctor that finds configuration that silently does nothing.
A sibling of agentcurfew: agentcurfew guards the files that steer AI coding agents, depcurfew guards the packages that people and agents install. Documentation: depcurfew.github.io.
On this page
Why
Package managers and update bots now each protect you against freshly published malicious versions: a release-age delay, an allow-list for install scripts, limits on git and tarball dependencies. Each tool names these settings differently, counts time in its own unit, reads them from its own files and supports them only from some version on. A setting can also look right and do nothing, for example because CI pins an older version of the package manager, or because a bot proposes versions the package manager would refuse.
depcurfew keeps one policy file, depcurfew.json, writes it into the configuration of every tool in the repository, and checks that the result really works.
What it stops and finds:
- Versions that are too new. Every package manager depcurfew configures and every update bot waits
cooldown.minimumbefore it takes a new version, each in its own setting, unit and file; pip waits where its environment sets the delay, whichapplynames. For the ecosystems whose package manager depcurfew does not configure, only the update bots wait. - Install scripts of dependencies that the policy does not allow, and Composer plugins.
- Git and tarball dependencies where the policy denies them.
- Look-alike and made-up names.
depcurfew check, the Claude Code hook and the MCP server stop a name one or two letters away from a popular npm package or PyPI project, the usual form of typosquatting and of package names an AI model invents. - Known malicious versions. After
depcurfew osv update, the same checks anddoctorblock the versions OSV.dev lists as malicious, offline, without sending a package name anywhere: see Known malicious versions. - Settings that do nothing.
doctorfinds a pinned package manager too old for a setting, a bot that waits less than the package manager, a CI job or Dockerfile that installs with another version, and more: see doctor rules.
Five-minute start
npx depcurfew doctorworks beforeinit: withoutdepcurfew.jsonit compares the repository with the policyinitwould write and shows, as notes in a block of their own, whatinitandapplywould change, for example a package manager that installs new versions without a release-age delay, with the settingsapplywould write for it. These notes never make it fail.npx depcurfew initwritesdepcurfew.jsonwith the default policy below and lists the tools it detected. When the repository already sets a longer release-age delay for one of them,cooldown.minimumkeeps the longest one, andinitsays where it found it.npx depcurfew explainshows what it detected and what the policy means for each tool.npx depcurfew apply --dry-runprints the changes as a diff, without writing anything.npx depcurfew applywrites them. Run it again wheneverdepcurfew.jsonchanges; a second run with the same policy changes nothing.npx depcurfew doctorreports configuration that silently does not work and drift from the policy, and exits with 1 when it finds an error or, with the"doctor": { "failOn": "warning" }thatinitwrites, a warning.- Add the GitHub Action so that doctor runs on every push and reports to code scanning.
The default policy:
{
"$schema": "https://unpkg.com/depcurfew/schema.json",
"version": 1,
"cooldown": {
"minimum": "3d",
"exclude": [],
"securityUpdates": "bypass"
},
"installScripts": {
"default": "deny",
"allow": [],
"deny": []
},
"sources": {
"git": "deny",
"remoteTarball": "deny",
"file": "allow",
"directory": "allow"
},
"targets": "auto",
"doctor": {
"failOn": "warning"
}
}
Documentation
The documentation site, depcurfew.github.io, shows these parts of this README on pages of their own:
- The policy file and Commands
- Supported tools and the knowledge base behind it
- doctor rules and the warnings and errors of init and apply
- GitHub Action, Guarding installs, Claude Code and the MCP server
- Protecting the whole machine
Installation
depcurfew runs on Node.js 18.3.0 or later, so it also works where a project or a coding agent still has an older Node.js (CI runs every command on the oldest version it supports), and has a single runtime dependency, yaml. Node.js 18 and 20 no longer get security fixes from the Node.js project; prefer a supported line where you can. Working on depcurfew itself needs Node.js 22.18 or later.
Add it to the project as a development dependency, so the team, CI and coding agents all run the version pinned in the lockfile. Once apply has written the project's release-age delay, later updates of depcurfew go through that delay as well:
npm install --save-dev --save-exact depcurfew
npx --no dcf doctor
dcf is the short name of the depcurfew program. Run it with npx --no: npm has an unrelated package named dcf, and where depcurfew is not installed yet (a fresh clone before npm ci, a repository without package.json), npx without --no would download and run that package instead, and in CI without asking. With --no, npx stops instead. The long name runs the same program, and npx --no depcurfew stops the same way.
Pin the exact version (--save-exact, or save-exact=true in .npmrc) and update it on purpose: depcurfew is a young project with frequent releases, and a range would let a new release in without review.
Who needs it installed:
- Developers working on the project: nothing to do. The protection does not depend on depcurfew being installed: it lives in the package manager configuration that
applywrites into the repository (.npmrc,package.json,pnpm-workspace.yaml,.yarnrc.yml,bunfig.toml,deno.json,pyproject.tomloruv.toml,poetry.toml,Pipfile,requirements.txt,composer.json,Gemfileorgems.rb,.cargo/config.toml, and the bot configuration), and the package managers read it on their own. pip's release-age delay is the exception: pip reads it only from the environment where it runs, andapplysays what to set there. The project install brings depcurfew along as a development dependency anyway. - Whoever changes
depcurfew.json: runsnpx --no dcf applyand commits the result. - CI: runs
doctor, with the GitHub Action below or with the project's own copy on other CI systems.
A global install (npm install -g depcurfew) works, but teams should not rely on it: each machine may run a different version, the lockfile does not pin it, and npm does not read the project's .npmrc in global mode, so the project's release-age delay does not cover the install.
To work on depcurfew itself, run it from a clone of this repository:
git clone https://github.com/DevXord/depcurfew.git
cd depcurfew
npm ci
npm run build
node dist/cli.js doctor /path/to/your/repository
In a repository without package.json
depcurfew is a Node.js program, and a repository without package.json in its root, such as a Rust, .NET, Python, PHP or Ruby project, does not need one to run it.
In GitHub Actions, the GitHub Action needs nothing installed.
Once, by hand, run an exact release with npx:
npx --yes depcurfew@1.5.2 doctor
Name a release that is at least as old as cooldown.minimum of the policy: depcurfew's own Claude Code hook denies a younger one, and so does npm where its min-release-age is set (npx then fails with ETARGET). The example names the newest release that was at least 7 days old when this README was written, usually the one before the newest. Without --yes, npx asks before it downloads a package the project does not have, and without a terminal or in CI it downloads without asking.
Pinned in the repository, keep depcurfew in the tools directory .claude/depcurfew: its own package.json pins depcurfew exactly, its package-lock.json is committed and .claude/depcurfew/node_modules is git-ignored. npm ci installs what that package-lock.json locks, and --prefix runs it in the tools directory, so both commands run from the root of the repository, without cd:
npm ci --ignore-scripts --prefix .claude/depcurfew
node .claude/depcurfew/node_modules/depcurfew/dist/cli.js doctor
doctor reads this copy too: depcurfew-outdated says when the depcurfew that runs is older than it, and the Claude Code hook can run it. To be offered new releases of the pin, you can add a Dependabot npm entry for the directory /.claude/depcurfew; apply gives it the cooldown of the policy like any other npm entry. The tools directory and the Action pin their versions separately, so update both.
Verifying a release
Every release is built and published from its git tag by the Release workflow with npm trusted publishing, so the npm page of each version shows its provenance: the repository, the workflow and the commit it was built from. One job of the workflow installs, tests and packs the package without the right to publish it. Before anything is staged, CHANGELOG.md must start with the section of the version, CI must have passed on the tagged commit (on Linux and Windows, down to the oldest Node.js the CLI supports), and another job must build the package again from a fresh checkout of the tag on another runner and get the same checksum. Only then does a last job, which runs no code of the repository or of its dependencies, stage exactly the file the first one packed, after comparing its SHA-512 checksum. After installing, npm audit signatures checks the registry signature and the provenance attestation of every installed package, depcurfew included.
The package contains nothing but the build of that commit, and anyone can check it: check out the tag, build it and compare the checksum with the one the registry serves:
git clone --branch v1.6.0 https://github.com/DevXord/depcurfew.git
cd depcurfew
npm ci --ignore-scripts
npm run build
npm pack --dry-run --json | grep shasum
npm view depcurfew@1.6.0 dist.shasum
The two checksums are the same. For 1.5.0 they differ: its JavaScript files are the build of the tag byte for byte, but its declaration file dist/index.d.ts lists the properties of the policy types in another order, which a build that ran right after the tests produced; later releases write those types out, so every build gives the same file. The Verify release workflow does this for the newest version on npm every day and on demand, and its runs are public in the Actions tab of the repository.
On this site
Start
- Step-by-step guide: From the first doctor run to CI, coding agents and the whole machine, one step at a time.
- Start with npm, pnpm, Yarn (Berry), Bun and Deno: The five-minute start, the settings and the doctor rules for npm, pnpm, Yarn (Berry), Bun and Deno.
- Start with uv, pip, Poetry, PDM and Pipenv: The five-minute start, the settings and the doctor rules for uv, pip, Poetry, PDM and Pipenv.
- Start with Composer: The five-minute start, the settings and the doctor rules for Composer.
- Start with Bundler: The five-minute start, the settings and the doctor rules for Bundler.
- Start with Cargo: The five-minute start, the settings and the doctor rules for Cargo.
- Start with Renovate and Dependabot: The five-minute start, the settings and the doctor rules for Renovate and Dependabot, also for Cargo, Go modules, Maven, Gradle and NuGet, which only the bots delay.
Reference
- The policy file: Every field of depcurfew.json, several projects in one repository, and the JSON Schema.
- Commands: Every command with its options, exit codes and JSON output.
- Warnings and errors of init and apply: Every code of the warnings, notes and errors of init and apply.
- doctor rules: Every rule of depcurfew doctor with its level and fix.
- Supported tools: What depcurfew configures and checks for each tool, with Python projects, update bots, Composer projects and Ruby projects.
- Knowledge base: Every fact depcurfew relies on, with its official source.
Integrations
- GitHub Action: The action with its inputs and outputs, and other CI systems.
- Guarding installs: depcurfew check before a package is installed.
- Claude Code: The Claude Code hook and how to set it up.
- MCP server: depcurfew mcp and how to add it to an MCP client.
- Protecting the whole machine: The user policy, the user file of each tool and the doctor --user rules.
Project
- About depcurfew: What depcurfew does not do, network and privacy, the library, contributing and the license.
- Alongside other supply-chain tools: How depcurfew works together with tools that inspect the packages themselves.
- Versions: The current version and the documentation of every earlier release.