Back to Function Hooks

Block Destructive Commands

Function Hooks security
Install Command
npx claude-code-templates@latest --function-hook security/block-destructive-commands
View on GitHub

Content

JSON
{
"description": "Denies Bash commands that match destructive patterns (recursive rm on roots, for..."
"modules": [
"./block-destructive-commands.ts"
]
}
Experimental. Function hooks are an Anthropic proposal under community review (anthropics/claude-code#91870), not a shipped feature. The modules key and every $ API name are provisional.

Module: hooks/block-destructive-commands.ts

ts
/**
 * block-destructive-commands — Function Hook (EXPERIMENTAL)
 *
 * Denies Bash commands that match destructive patterns before they run.
 * Placement: "instead" (returns { deny } without calling next) on a match,
 * pass-through otherwise.
 *
 * Function hooks are an Anthropic proposal under community review:
 * https://github.com/anthropics/claude-code/issues/91870
 * Every API name below is provisional.
 */

// Provisional typings. Claude Code will ship real ones with the feature.
type Engine = any;
type Next = ((e: any) => Promise<any>) & { event: string; origin: string; signal: AbortSignal };

interface Rule { pattern: RegExp; reason: string }

const DEFAULT_RULES: Rule[] = [
  // rm with a recursive flag anywhere in its arguments (-r, -rf, -r -f, --recursive, -fR ...)
  // and a root/home/cwd target, optionally quoted or with a trailing slash ("~/", "$HOME/", "/").
  { pattern: /\brm\s+(?=(?:\S+\s+)*?(?:-[a-z]*r[a-z]*|--recursive)\b)(?:\S+\s+)*?["']?(?:\/|~|\$HOME|\$\{HOME\}|\.\.?)\/?["']?(?:\s|$|;|&|\|)/i, reason: "recursive delete of a root, home or working directory" },
  { pattern: /\brm\s+.*--no-preserve-root\b/i, reason: "rm with --no-preserve-root" },
  { pattern: /\bgit\s+push\b(?!.*--force-with-lease).*(--force\b|\s-f\b)/, reason: "force push" },
  { pattern: /\bgit\s+(reset\s+--hard|clean\s+-[a-z]*f)/, reason: "history or working-tree destruction" },
  { pattern: /\b(DROP|TRUNCATE)\s+(TABLE|DATABASE|SCHEMA)\b/i, reason: "destructive SQL" },
  { pattern: /\bmkfs(\.|\s)/, reason: "filesystem format" },
  { pattern: /\bdd\s+.*\bof=\/dev\//, reason: "raw disk write" },
  { pattern: /\bchmod\s+(-R\s+)?777\b/, reason: "world-writable permissions" },
];

export function register(on: any, options: Record<string, any> = {}) {
  // Extra patterns come from the plugin's userConfig, e.g. { "patterns": ["\\bkubectl\\s+delete\\b"] }
  const custom: Rule[] = (options.patterns ?? []).map((p: string) => ({
    pattern: new RegExp(p),
    reason: `custom pattern ${p}`,
  }));
  const rules = [...DEFAULT_RULES, ...custom];

  on("tool.call", { tool: "Bash" }, ($: Engine, e: any, next: Next) => {
    const command: string = e.command ?? "";

    for (const { pattern, reason } of rules) {
      if (pattern.test(command)) {
        $.ui.log(`[block-destructive-commands] denied Bash call: ${reason}`);
        return {
          deny: `Blocked by block-destructive-commands (${reason}). ` +
            `If this is intentional, ask the user to run it manually.`,
        };
      }
    }

    // Nothing matched: let the rest of the chain (and the real tool) run.
    return next(e);
  });
}

Stack Builder

0 components

Your stack is empty

Browse components and click the + button to add them to your stack for easy installation.