Block Git Commands in a Repo With a Config-Driven Execution Payload

Security researchers (Manifold Security, Sept 2026) showed that a malicious .git/config checked into a repo — a core.fsmonitor, core.pager, core.sshCommand, or alias.* entry with a leading '!' — can run an arbitrary command the moment an agent issues an ordinary git status, fetch, or push, with no commit or checkout required to trigger it. An executable file under .git/hooks/ (beyond the stock .sample files) is the same risk on the next commit/checkout. This scans both before letting any Bash call containing 'git' through, which matters most right after an agent clones or is pointed at a repo it hasn't reviewed yet.

Worktree & Git Safety Event: PreToolUse Claude Code Open source · Free

1. Save this as the hook script

#!/usr/bin/env python3
"""PreToolUse hook — before letting a Bash tool call run a `git` subcommand,
scans the repo's .git/config and .git/hooks/ for the config-driven RCE
pattern disclosed by security researchers in 2026: a cloned repo can ship
a .git/config with a core.fsmonitor, core.pager, core.sshCommand, or
alias.* entry that runs an arbitrary command the moment an ordinary git
command (status, fetch, push) runs — and/or a non-sample, executable file
under .git/hooks/ that fires on the next commit/checkout. Wire this to
matcher "Bash"; it only inspects when the command string contains "git"."""
import json, re, sys, stat
from pathlib import Path

data = json.load(sys.stdin)
command = data.get("tool_input", {}).get("command", "")
if "git" not in command:
    sys.exit(0)

cwd = Path(data.get("cwd", "."))
git_dir = cwd / ".git"
if not git_dir.exists():
    sys.exit(0)

findings = []

config_path = git_dir / "config"
if config_path.exists():
    config_text = config_path.read_text(errors="ignore")
    for pattern in (r"core\.fsmonitor\s*=", r"core\.pager\s*=",
                    r"core\.sshCommand\s*=", r"alias\.\w+\s*=\s*!"):
        if re.search(pattern, config_text):
            findings.append(f"suspicious .git/config entry matching {pattern}")

hooks_dir = git_dir / "hooks"
if hooks_dir.exists():
    for f in hooks_dir.iterdir():
        if f.name.endswith(".sample") or not f.is_file():
            continue
        if f.stat().st_mode & stat.S_IXUSR:
            findings.append(f"executable git hook present: {f.name}")

if findings:
    print("BLOCKED: this repo's .git/ directory has config-driven execution "
          "risk before any git command runs:\n  - " + "\n  - ".join(findings),
          file=sys.stderr)
    sys.exit(2)

sys.exit(0)

Save to a path inside your project, e.g. .claude/hooks/block-git-config-rce-payload.sh, then chmod +x it.

2. Wire it into .claude/settings.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {"type": "command", "command": "python3 .claude/hooks/block-git-config-rce-payload.py"}
        ]
      }
    ]
  }
}

Before you use this

A hook runs with your local shell's permissions — review the script above before adding it, the same way you'd review any script you didn't write yourself. See our guide on hook security risks for the specific CVEs this category of feature has already produced.

Related hooks

← All hooks
FEEDBACK