Skip to content

RefuseHQ/refuse-cli

refuse-cli

Wraps npm, pip, cargo, yarn, pnpm, gem, bun, and go as a PATH shim — refuses to install packages with known CVEs.

CI Lint CodeQL Release Go Reference License: Apache-2.0

$ npm install lodash@4.17.10
refuse: blocked — CVE-2019-10744 (high)
        Prototype pollution in lodash <= 4.17.11
        suggested safe version: 4.17.21

refuse sits in front of your package managers. Every install call is vetted against a refuse server (self-hosted) or refuse.dev (hosted) before the real binary runs. If the package has a known advisory above your severity threshold, the install is blocked with the CVE and a suggested safe version.

Works:

  • On a developer's laptop.
  • In a CI runner.
  • Inside a Docker build stage.
  • As a Claude Code PreToolUse hook — same gate for autonomous agent installs.

Install

Homebrew (macOS):

brew install refusehq/tap/refuse

Direct binary on macOS / Linux (with sha256 checksum verification):

curl -sSL https://raw.githubusercontent.com/RefuseHQ/refuse-cli/main/scripts/install.sh | sh

Direct binary on Windows (PowerShell, with sha256 checksum verification):

irm https://raw.githubusercontent.com/RefuseHQ/refuse-cli/main/scripts/install.ps1 | iex

From source:

go install github.com/RefuseHQ/refuse-cli/cmd/refuse@latest

Verified releases are cosign-signed with SLSA build provenance — see SECURITY.md for the verification command.

Platforms. Pre-built binaries are published for:

OS Architectures
macOS x86_64, arm64
Linux x86_64, arm64, i386, armv6, armv7
Windows x86_64, arm64, i386

Other platforms can go install from source.

Quickstart

refuse init                       # interactive: server URL + API key
refuse install                    # writes shims to ~/.refuse/bin + updates PATH
refuse hook install claude-code   # PreToolUse hook in ~/.claude/settings.json

Then run anything you'd normally run:

npm install express
pip install requests
cargo add tokio

If the install is clean, it goes through. If it isn't, refuse blocks it and tells you why.

How it works

flowchart LR
    USER[Developer] -->|"npm install …"| SHIM[refuse-cli<br/>aliased as 'npm']
    AGENT[Coding agent] -->|PreToolUse hook| GATE[refuse gate]
    SHIM --> PARSE[parser]
    GATE --> PARSE
    PARSE -->|"(eco, name, ver)"| DECIDE[decide]
    DECIDE -->|HTTP| SERVER[(refuse server)]
    SERVER -->|verdict| DECIDE
    DECIDE -->|allow| REAL[real binary]
    DECIDE -->|block exit 2| FAIL[stderr]
Loading

A single Go binary, symlinked into ~/.refuse/bin/ under each manager's name. When npm is invoked, the shim parses the argv, asks the server, and either execs the real npm on PATH or exits with code 2 and a message.

For details, see ARCHITECTURE.md.

Supported package managers

Manager Ecosystem Install verbs Lockfile parsing
npm npm install, i, add package-lock.json
pnpm npm install, add pnpm-lock.yaml
yarn (classic + Berry) npm add, install yarn.lock
bun npm install, add bun.lockb / bun.lock
pip / pip3 PyPI install, install -r requirements.txt
cargo crates.io add, install Cargo.lock
gem RubyGems install Gemfile.lock
go Go modules get, install go.sum

Supported agent hooks

Agent Status
Claude Code ✓ supported
Cursor tracked in #?
Continue tracked
Aider tracked
Codex CLI tracked
Cline tracked

PRs welcome — see internal/hook/claudecode.go as the reference.

Commands

Command What it does
refuse init First-time setup wizard
refuse install Install shims for the supported package managers
refuse uninstall Remove shims + revert shell-rc edits
refuse hook install <agent> Write a pre-tool-use hook for <agent>
refuse hook remove <agent> Remove that hook
refuse hook list Show all installed hooks
refuse check <eco> <pkg>[@<ver>] One-off check
refuse check-lockfile <path> Scan an entire lockfile
refuse gate The decision engine — shims + hooks call this on stdin
refuse config show | set | get Manage ~/.refuse/config.yaml
refuse status Diagnose install state
refuse doctor Verify PATH / hooks / server reachability

Configuration

refuse config set <key> <value>, or edit ~/.refuse/config.yaml directly:

server_url: http://localhost:8080        # or https://mcp.refuse.dev
api_key: rfs_...                         # optional, required for hosted
policy:
  severity_threshold: high               # low | medium | high | critical
  fail_closed: false                     # true = block if server unreachable (default false → fail open with stderr warning)
  allow_yanked: false                    # allow yanked versions when no advisory matches
  allow_prerelease: false                # allow prerelease versions
  override_env: REFUSE_ALLOW_VULNERABLE  # env var that forces a block to pass through

Environment variables override the file (useful in CI):

  • REFUSE_SERVER_URL
  • REFUSE_API_KEY
  • REFUSE_POLICY — sets severity_threshold
  • REFUSE_FAIL_CLOSED1/true to enable
  • REFUSE_ALLOW_VULNERABLE1/true to bypass a single install

Pointing at a server

Hosted (refuse.dev):

refuse config set server_url https://mcp.refuse.dev
refuse config set api_key rfs_...

Self-hosted (RefuseHQ/refuse):

docker run --rm -p 8080:8080 ghcr.io/refusehq/refuse:latest
refuse config set server_url http://localhost:8080

In CI

# .github/workflows/ci.yaml
jobs:
  install:
    runs-on: ubuntu-latest
    env:
      REFUSE_SERVER_URL: https://mcp.refuse.dev
      REFUSE_API_KEY: ${{ secrets.REFUSE_API_KEY }}
    steps:
      - uses: actions/checkout@v4
      - name: Install refuse
        run: curl -sSL https://raw.githubusercontent.com/RefuseHQ/refuse-cli/main/scripts/install.sh | sh
      - run: $HOME/.refuse/bin/refuse check-lockfile package-lock.json   # exits 2 on a vulnerable hit
      - run: npm ci

How it relates to the other refuse projects

What it is When to use it
refuse-cli (this) PATH shim in front of package managers You want to block installs before they happen, on a laptop / CI / Docker build
refuse Self-hostable HTTP server You want to run your own backend
refuse.dev Hosted service You don't want to run anything; sign up and point the CLI at it

Status

Alpha. The gate is production-ready; some convenience subcommands are still being filled in. See ROADMAP.md and open issues for the path to 0.1.0.

Contributing

PRs welcome — particularly for new package managers, agent hooks, and platforms. See CONTRIBUTING.md.

Security

Security policy: SECURITY.md. Report privately via hello@refuse.dev.

License

Apache License 2.0 © RefuseHQ.

About

Wraps npm, pip, cargo, yarn, pnpm, gem, bun, and go as a PATH shim — refuses to install packages with known CVEs.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors