How to block dangerous Bash commands in Claude Code

Most Claude Code accidents are not exotic. They are an ordinary cleanup command with a slightly wrong target, or a "start clean" that throws away uncommitted work. A PreToolUse hook on the Bash tool can catch the common ones before they run.

The failures worth catching

A short list covers most of the real risk in a Next.js project:

How the hook works

Claude Code sends the pending command to your script as JSON on stdin. If the script exits with code 2, the command does not run and the script's stderr is returned to Claude. Write the message so it explains the rule and offers a safer route, for example "ask the user to run the deploy themselves".

// .claude/hooks/guard-bash.mjs (sketch)
import { readFileSync } from "node:fs";

const { tool_input } = JSON.parse(readFileSync(0, "utf8"));
const cmd = tool_input?.command ?? "";

const rules = [
  [/git\s+push\b.*(--force\b(?!-with-lease)|\s-f\b)/, "force push is blocked; use --force-with-lease"],
  [/git\s+reset\s+--hard/, "reset --hard discards uncommitted work"],
  [/\b(npm|pnpm|yarn|bun)\s+publish\b/, "publishing is a human decision"],
];

for (const [re, why] of rules) {
  if (re.test(cmd)) {
    console.error(`guard-bash: ${why}`);
    process.exit(2);
  }
}

Register it under PreToolUse with a Bash matcher in .claude/settings.json, then restart Claude Code and confirm with /hooks.

It is pattern matching, not a sandbox

This is the important caveat. A regex guard catches the common mistakes and nothing more. A command rephrased to get around the pattern can slip past, and a chained command can defeat a denylist. Treat the hook as a seatbelt, not a wall:

When it blocks something safe

Every block message should name the hook and the rule, so you can see why it fired. Your options are to run the command yourself in a terminal, or to edit the rule. If you want Claude to deploy, for example, remove the publish and production-deploy rule on purpose, and re-run any test that covered it so the change is deliberate.

Going further

A tested version of this guard, with the rules above and self-tests for each, ships in the Next.js Claude Code workflow pack.

This article was written with AI assistance.