GitSpawn: AI Coding Agent Git-Config RCE

A booby-trapped repository's own .git/config (via core.fsmonitor, core.hooksPath, attr.tree, or clean/process filters) makes an AI coding agent's routine background git status/git diff execute an attacker-supplied program: as the logged-in user, outside the agent's sandbox, with no approval prompt.
Threat
GitSpawn: multi-agent git-config RCE class
Severity
HIGH · Sandbox-Escape RCE (GitSpawn's own CVEs: 7.3 Codex, 7.0 Goose) · Responsible disclosure, no confirmed ITW
Type
Developer-tooling / supply-chain-adjacent RCE
Access
Local execution via received repo · no network exploit
Version
v0.1 · 2026-09-25
Author
HuntPack
Confidence
High (behavioral) · No atomic infrastructure IOCs published
01

Executive Summary

On 2026-09-01, Manifold Security disclosed GitSpawn: a vulnerability class affecting seven AI coding agents (Claude Code, OpenAI Codex, Cursor, Goose, Hermes Agent, Qwen Code, Grok Build) across eight distinct findings. Every one of these agents gathers project context by quietly running git status / git diff in the background: often before the user has typed a prompt, accepted a workspace-trust dialog, or authenticated. Git supports core.fsmonitor, a legitimate performance setting naming a helper program that git launches automatically whenever it refreshes its index. That value is read straight out of the repository's own .git/config. A malicious repository can set it (or the related core.hooksPath, attr.tree, or a clean/process filter command) to an attacker-chosen program, and the moment the agent's background git command touches that repo, the program runs: as the logged-in user, outside the agent's sandbox, and invisible to the agent's own permission/approval system.

Four of the eight findings were still unpatched at publication (Claude Code's second "ultrareview" path, Hermes Agent, Qwen Code, Grok Build). Two formal CVEs anchor the disclosure: CVE-2026-19592 (OpenAI Codex CLI/Desktop, CVSS 7.3, fixed 0.131.0) and CVE-2026-72718 (Goose, fixed 1.44.0). A related, separately-tracked Claude Code vulnerability, CVE-2026-55607 (git-worktree path confusion abusing the same fsmonitor execution sink, CVSS 8.8, fixed 2.1.163), shares the mechanism but a different delivery chain (requires a clone plus prompt-injection content, not merely opening a received folder): see §2 for the reconciliation.

Delivery reality: this cannot arrive via an ordinary git clone, fetch, or pull, since none of those transmit a hostile .git/config. The repository has to arrive as files with its .git directory already inside, exactly how developers routinely receive projects: a zipped project handoff from a contractor, a synced cloud-drive share, a "bug report" archive from a stranger, or a USB stick.

Defender priority: there are no published C2 domains, IPs, or file hashes for this research: the atomic surface is configuration strings and affected agent version numbers, not infrastructure, and the sensor cannot see the contents of a git config file it did not observe being written. The hunt is therefore behavioral: unexpected process ancestry (agent → git → shell/interpreter/network tool), archive extraction immediately preceding a git/agent launch, and the follow-on credential-access and persistence an attacker would chase once code execution lands. Patch/version-pin every affected agent (§12) and inspect .git/config in any repository received as files before opening it in an agent.

02

Source Review & Web Hunter Notes

TierSourceKey FindingCarry Forward
PrimaryManifold Security: "GitSpawn" (2026-09-01)Original disclosure: mechanism, 8 findings / 7 agents, delivery vector, vendor + recipient mitigation languageYes
NewsThe Hacker News (2026-09-02)Per-agent affected/fixed version table; timeline; core.hooksPath/attr.tree named as additional sinksYes
NewsShattered.ioCorroborates patch-status table and "does not survive git clone" framingYes
NewsByteIotaCorroborates mechanism and agent list. Two claims dropped: an uncorroborated "FakeGit campaign, 7,600+ poisoned repos" statistic and a Codex CLI "0.152.1+" patch figure that conflicts with the formal CVE record (08) and The Hacker News (02): neither ships anywhere in this packPartial
NewsCybersecuritynews.comCorroborates mechanism, "cannot arrive via clone/fetch/pull" delivery-reality language (used near-verbatim in §1/§3), 77M+ monthly npm downloads context for Claude CodeYes
NewsGBHackersThird corroboration of per-agent affected/fixed version numbersYes
Vendor CVEGitLab Advisory DB: CVE-2026-55607Claude Code sandbox escape via git-worktree path confusion; CVSS 8.8; affected 2.1.38–2.1.162, fixed 2.1.163; requires clone + prompt injection (different delivery chain than the core GitSpawn disclosure: see reconciliation below)Yes, with caveat
Vendor CVEOpenCVE: CVE-2026-19592Authoritative Codex CLI/Desktop affected + fixed version numbers, CVSS 7.3, CWE-15Yes

Reconciliation note: CVE-2026-55607 is related but distinct: Manifold's GitSpawn disclosure says Claude Code's core.fsmonitor path was fixed in 2.1.196 (with a second "ultrareview" path reportedly still live at 2.1.252). CVE-2026-55607 was fixed earlier, in 2.1.163, via a different delivery chain: cloning a malicious repo containing prompt-injection content that steers the agent into vulnerable worktree operations, not simply opening a received folder. This pack cites CVE-2026-55607 for its fsmonitor-abuse detection and hardening value (§6, §9, §12) while keeping its version numbers and delivery chain clearly separate from the GitSpawn-labeled Claude Code findings.

IOC provenance note: no cited source publishes atomic infrastructure indicators (attacker IPs, C2 domains, malware hashes) for GitSpawn: the "indicators" are affected-version strings and the git config keys themselves. §10's Falcon IOC Management CSV block is therefore placeholder-only by design; §4 and §10's behavioral/config blocks are the operative content.

03

Hunt Brief & Attack Chain

The exploit itself is nothing more than a few text lines in a file the victim already has on disk. All of the detectable behavior happens after an AI coding agent's routine background git command reads that file and launches whatever it names.

Hunt hypotheses (highest fidelity first)

#HypothesisMITRETelemetryConf
H1An AI coding agent binary is the grandparent of git, which is the parent of an interactive shell or scripting interpreter: the core fsmonitor/hooksPath/attr.tree execution chainT1059 / T1195ProcessRollup2High
H2git spawns a child that is not one of its own known helpers: curl/wget, a LOLBin, or a shell: matching a config-named helper program rather than a normal git subprocessT1059 / T1105ProcessRollup2High
H3git is invoked with an explicit -c core.fsmonitor=/-c core.hooksPath=/-c attr.tree= override on the command line (attacker automation, or: legitimately: the vendor-recommended mitigation check)T1059ProcessRollup2Medium
H4An archive-extraction utility (tar/unzip/7z/ditto/Expand-Archive) runs immediately before a git or AI-agent process launches on the same host: the only way this payload can be deliveredT1204.002 / T1027ProcessRollup2Medium
H5A process descended from git accesses SSH keys, cloud credential files, or git-credential stores shortly after the execution chain firesT1552.001 / T1552.004ProcessRollup2High
H6git is used to create a worktree named/pathed as .git (CVE-2026-55607-class path confusion) ahead of an fsmonitor executionT1036.005 / T1211ProcessRollup2High
H7A shell/interpreter descended from git makes an outbound network connection: staging a second-stage payload or reaching back to attacker infrastructureT1105 / T1071ProcessRollup2 + NetworkConnectIP4Medium
H8A process descended from git or an AI agent rewrites a shell profile / dotfile (.zshenv, .bash_profile, .profile) for persistence: the exact technique CVE-2026-55607 used to escape the sandboxT1546.004ProcessRollup2High
H9A Windows Run-key or scheduled-task entry is created within minutes of a suspicious git-ancestry process on the same hostT1547.001 / T1053.005Reg/Asep + ScheduledTaskRegisteredMedium

Attack chain

StepActionTelemetryHunt Angle
1 · PrepareAttacker crafts a repo whose .git/config names a helper under core.fsmonitor (or hooksPath/attr.tree/filter)None on the victim's EDR: happens on attacker infrastructureNo detectable telemetry pre-delivery
2 · DeliverRepo handed off as a zip/synced-folder/USB with .git intact: not a clone/fetch/pullArchive-extraction process; file-system write of the folderH4: extraction immediately preceding git/agent launch
3 · TriggerVictim opens the folder in an AI coding agent; the agent runs a background git status/git diff for contextProcessRollup2 (git launch)H3: explicit config override on the git command line, where visible
4 · Executegit reads .git/config, launches the named helper: the RCE moment: as the logged-in user, outside the agent sandboxProcessRollup2 (agent → git → shell/interpreter)H1/H2/H6: the core execution-chain hunts
5 · Stage/CallbackSpawned shell/interpreter reaches out for a second-stage payload or C2NetworkConnectIP4 from a git-descended shellH7
6 · Harvest/PersistCredential-file access, dotfile rewrite, or Run-key/scheduled-task creationProcessRollup2 / Reg / Asep / ScheduledTaskRegisteredH5/H8/H9
04

Consolidated IOC Table

No cited source publishes atomic infrastructure indicators (attacker IPs, C2 domains, malware file hashes) for GitSpawn. The "indicators" that exist are affected-component version numbers and the git configuration keys the attack abuses: both are config/behavioral, and both trace directly to the saved source snapshots. Atomic-IOC rows are intentionally omitted rather than fabricated.

TypeValue / PatternConfidenceActionContext
Config keycore.fsmonitor naming a program in a received repo's .git/configHighhuntPrimary GitSpawn sink (source 01/02)
Config keycore.hooksPath, attr.tree, or a clean/process filter command in .git/config / .gitattributesMediumhuntAdditional sinks reported by Manifold (source 01/02)
VersionClaude Code (fsmonitor path) < 2.1.196HighdetectFixed 2.1.196; ultrareview path unpatched at 2.1.252 (source 01/02/03)
VersionClaude Code 2.1.38 – 2.1.162 (CVE-2026-55607)HighdetectFixed 2.1.163; worktree path-confusion, CVSS 8.8 (source 07)
VersionGoose < 1.44.0 (CVE-2026-72718)HighdetectFixed 1.44.0, severity 7.0 (source 01/02/06)
VersionCodex CLI 0.102.0 – 0.130.0 (CVE-2026-19592)HighdetectFixed 0.131.0, CVSS 7.3 (source 02/08)
VersionCodex Desktop macOS ≤ 26.513.31313 / Windows ≤ 26.513.40821HighdetectFixed 26.519.22136 (macOS) / 26.519.21041 (Windows) (source 02/08)
VersionHermes Agent 0.18.2 – 0.21.0 (CVE-2026-71963)MediumhuntUnpatched at publication, vendor unresponsive (source 01/02/06)
VersionQwen Code 0.19.6 – 0.22.3MediumhuntUnpatched at publication, no CVE assigned (source 01/02/06)
VersionGrok Build 0.2.93 – 1.0.13MediumhuntUnpatched at publication, no CVE assigned (source 01/02/06)
BehaviorArchive-extraction process immediately followed by a git/agent launch on the same hostMediumhuntThe only viable delivery path (source 01/02/05)
05

Affected Surface & Telemetry Matrix

SurfaceRequired TelemetryPriorityGap Risk
Windows developer endpoints (Claude Code, Codex, Cursor, Grok Build, etc. under Node/Electron)ProcessRollup2, NetworkConnectIP4, AsepValueUpdate/RegGenericValueUpdate, ScheduledTaskRegisteredCriticalLow: Falcon-native
macOS developer endpointsProcessRollup2 (zsh/bash/osascript ancestry), NetworkConnectIP4CriticalLow: Falcon-native; sandboxed-app nuances per CVE-2026-55607
Linux developer endpointsProcessRollup2 (sh/bash/zsh ancestry), NetworkConnectIP4CriticalLow: Falcon-native
The repository's own .git/config contentsNone: Falcon does not inspect file contents at restCriticalHigh: sensor sees the process that reads/writes the file, not its contents; no CQL query in §8 can confirm what value core.fsmonitor actually held
Archive/zip handling (email gateway, cloud-drive sync, USB)Process telemetry for the extraction tool onlyMediumMedium: depends on endpoint coverage of the sync/USB path

There is no attacker infrastructure to hunt for and no C2 domain/IP/hash to import. The single most valuable action for this pack is inventorying which AI coding agents run on which endpoints, at which versions (§10's audit block): that inventory is what turns §8's queries from "any git process" into "a specific unpatched agent's git process."

06

ATT&CK Mapping

TacticTechniqueObserved BehaviorQuery / Control
Initial Access / ExecutionT1195 Supply Chain Compromise / T1059 Command & Scripting InterpreterAgent's background git command triggers an attacker-named fsmonitor/hooksPath helperQ1
ExecutionT1059 (LOLBins / interpreters spawned by git)git's child process is not a known git helperQ2
ExecutionT1059 (explicit config override)git invoked with -c core.fsmonitor=/hooksPath/attr.treeQ3
Initial AccessT1204.002 Malicious File / T1027 Obfuscated FilesArchive extraction delivering a .git directory just ahead of a git/agent launchQ4
Credential AccessT1552.001 Credentials in Files / T1552.004 Private KeysProcess descended from git touches SSH keys / cloud credential filesQ5
Defense Evasion / PersistenceT1036.005 Match Legitimate Name / T1211 Exploitation for Defense EvasionWorktree created named/pathed .git (CVE-2026-55607-class)Q6
Command & ControlT1105 Ingress Tool Transfer / T1071 Application Layer ProtocolOutbound connection from a shell/interpreter descended from gitQ7
PersistenceT1546.004 Unix Shell Configuration ModificationDotfile (.zshenv/.bash_profile/.profile) rewritten by a git/agent-descended processQ8
PersistenceT1547.001 Registry Run Keys / T1053.005 Scheduled TaskRun-key or scheduled-task creation near a suspicious git-ancestry processQ9
07

Native Audit-Log Hunts (non-CQL)

These checks give you ground truth on exactly what Falcon cannot see: the actual contents of a repository's .git/config, and which AI coding agent build is installed. Run before, or alongside, the CQL in §8.

Inspect a received repository before opening it in an agent (any platform)

git config --get core.fsmonitor
git config --get core.hooksPath
git config --get attr.tree
grep -nE "fsmonitor|hooksPath|\[filter" .git/config .gitattributes 2>/dev/null
# Any output naming an external program is a hold-and-review, not an open-in-agent.

Vendor-recommended safe context-gathering (per Manifold / The Hacker News)

# Strip the sink on any ad hoc background git command:
git -c core.fsmonitor=false status
git -c core.fsmonitor=false diff
# Set a permanent default until every agent in use is confirmed patched:
git config --global core.fsmonitor false

Inventory installed AI coding agent versions (run fleet-wide via RMM/MDM)

claude --version
codex --version
cursor --version
goose --version
grok-build --version 2>/dev/null
qwen-code --version 2>/dev/null
# Compare output against the affected/fixed table in Section 4 and the audit block in Section 10.

macOS-specific: confirm sandbox/seatbelt profile is current (CVE-2026-55607 surface)

  • Confirm Claude Code is at 2.1.163+ (CVE-2026-55607) and 2.1.196+ (GitSpawn core.fsmonitor path): both are required; they are different fixes.
  • Review ~/.zshenv, ~/.zprofile, and ~/.bash_profile for unexpected recent modification timestamps.
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.
This is a behavioral hunt: there are no atomic IOCs to filter on. Every query below matches process ancestry and command-line shape, not a known-bad hash or address. Developer endpoints are inherently noisy for git activity, so every card with FP medium+ carries a // TUNING: exclusion: read it before you deploy.
Q1 · AI coding agent → git → shell/interpreter (core execution chain)
CONF HIGHFP MEDCOST LOW

Looks for: the exact GitSpawn execution chain: an AI coding agent binary as the grandparent, git as the parent, and a shell or scripting interpreter as the child. This is the moment core.fsmonitor/core.hooksPath/attr.tree actually fires. FP: git hooks, aliases, and editor integrations legitimately spawn shells; tune the agent-binary and shell lists to your fleet's actual toolset.

// HUNT: AI coding agent -> git -> shell/interpreter (GitSpawn core execution chain)
// MITRE: T1059, T1195
// CONF: high  FP: medium  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
// FALSE POSITIVES: legitimate git hooks, shell aliases, editor/IDE git integrations spawning a shell
// TUNING: narrow GrandparentBaseFileName to the agent binaries actually deployed in your fleet; exclude known internal hook scripts by ParentCommandLine
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| GrandparentBaseFileName=/^(claude|claude-code|node|codex|codex-cli|cursor|cursor-agent|goose|goosed|hermes|hermes-agent|qwen-code|qwen|grok-build|grok)(\.exe)?$/i
| ParentBaseFileName=/^git(\.exe)?$/i
| FileName=/^(cmd|powershell|pwsh|wscript|cscript|mshta|rundll32|regsvr32)\.exe$|^(sh|bash|zsh|dash|osascript|python3?|perl|ruby|node)$/i
| table([ComputerName, UserName, GrandparentBaseFileName, ParentBaseFileName, FileName, CommandLine, ParentCommandLine], limit=200)
Q2 · git spawning an unexpected non-helper child
CONF HIGHFP MEDCOST LOW

Looks for: git launching a child that is neither an interactive shell (covered by Q1) nor one of git's own known helper binaries: a download tool, LOLBin, or scripting host, which is what a core.fsmonitor/hooksPath program typically resolves to when it isn't a plain shell. FP: credential-manager helpers and SSH askpass programs; the explicit helper exclusion keeps this narrow, but confirm your environment's git-credential-manager binary name is covered.

// HUNT: git spawns a child that is not a known git helper (fsmonitor/hooksPath payload)
// MITRE: T1059, T1105
// CONF: high  FP: medium  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
// FALSE POSITIVES: git-credential-manager/askpass helpers not covered by the exclusion list below
// TUNING: add your credential-manager/askpass binary name to the FileName!= exclusion before deploying as a Detect IOA
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^git(\.exe)?$/i
| FileName=/^(curl|wget|certutil|bitsadmin|mshta|rundll32|regsvr32|powershell|pwsh|cmd)\.exe$|^(curl|wget|sh|bash|zsh|python3?|osascript|nc|ncat|socat)$/i
| FileName!=/^git-(remote-https|remote-http|credential-.*|upload-pack|receive-pack|shell|sh)(\.exe)?$/i
| table([ComputerName, UserName, ParentBaseFileName, FileName, CommandLine, ParentCommandLine], limit=200)
Q3 · git invoked with an explicit dangerous config override
CONF MEDFP MEDCOST LOW

Looks for: a git command line that sets core.fsmonitor, core.hooksPath, or attr.tree via -c: could be attacker automation staging the sink, or an analyst/engineer legitimately running the vendor-recommended git -c core.fsmonitor=false status mitigation. FP: the vendor mitigation itself will match; triage by whether the value is being set to a program (bad) or disabled (expected/good).

// HUNT: git invoked with -c core.fsmonitor=/-c core.hooksPath=/-c attr.tree= on the command line
// MITRE: T1059
// CONF: medium  FP: medium  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
// FALSE POSITIVES: the vendor-recommended mitigation "git -c core.fsmonitor=false status" matches this pattern and is expected/benign
// TUNING: exclude CommandLine containing "fsmonitor=false" to isolate the risky (non-"false") sets from the benign mitigation runs
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^git(\.exe)?$/i
| CommandLine=/-c\s+(core\.fsmonitor|core\.hooksPath|attr\.tree)\s*=/i
| table([ComputerName, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q4 · Archive extraction immediately followed by a git/agent launch (delivery vector)
CONF MEDFP HIGHCOST MED

Looks for: the only viable delivery path for GitSpawn: a repository arriving as an archive (zip, tar, 7z) that already contains a .git directory, unpacked immediately before a git or agent process launches on the same host. This cannot happen via git clone. FP: high: routine project setup, dependency installs, and CI runners unpacking build artifacts all match; the join correlates by host only, not by directory, so run it over a narrow window.

// HUNT: Archive extraction immediately followed by git or AI-agent process launch (delivery vector)
// MITRE: T1204.002, T1027
// CONF: medium  FP: high  COST: medium | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
// FALSE POSITIVES: routine project setup (dependency installs unpacking archives), CI runners unzipping build artifacts, legitimate contractor handoffs
// TUNING: run over a narrow window (console time picker, 30-60 min) so the join only correlates temporally close events; exclude CI/build-agent hosts by ComputerName and known software-distribution paths by CommandLine
// LOOKBACK: run over 30-60m, not the default -- see TUNING
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^git(\.exe)?$/i OR GrandparentBaseFileName=/^(claude|claude-code|node|codex|cursor|goose|hermes|qwen-code|grok-build)(\.exe)?$/i
| join(query={
    #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
    | FileName=/^(tar|unzip|7z|7za|ditto|winrar)(\.exe)?$/i OR FileName=/^Expand-Archive$/i
    | rename(field=FileName, as=ExtractTool)
    | rename(field=CommandLine, as=ExtractCommandLine)
    | table([aid, ExtractTool, ExtractCommandLine])
  }, field=aid, include=[ExtractTool, ExtractCommandLine], mode=inner)
| table([ComputerName, UserName, FileName, CommandLine, ParentBaseFileName, GrandparentBaseFileName, ExtractTool, ExtractCommandLine], limit=200)
Q5 · Credential/secret file access by a process descended from git
CONF HIGHFP LOWCOST LOW

Looks for: the natural next step after landing code execution through GitSpawn: reading SSH private keys, cloud CLI credential files, npm/git credential stores, or netrc. FP: low; legitimate tooling rarely references these exact paths on the command line.

// HUNT: Credential/secret file access by a process descended from git (post-compromise credential harvesting)
// MITRE: T1552.001, T1552.004, T1555
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^git(\.exe)?$/i OR GrandparentBaseFileName=/^git(\.exe)?$/i
| (CommandLine="*.ssh/id_rsa*" OR CommandLine="*.ssh\\id_rsa*" OR CommandLine="*.ssh/id_ed25519*" OR CommandLine="*.aws/credentials*" OR CommandLine="*.aws\\credentials*" OR CommandLine="*.config/gcloud*" OR CommandLine="*.npmrc*" OR CommandLine="*.netrc*" OR CommandLine="*.git-credentials*")
| table([ComputerName, UserName, ParentBaseFileName, GrandparentBaseFileName, FileName, CommandLine], limit=200)
Q6 · Git worktree path confusion (CVE-2026-55607-class)
CONF HIGHFP LOWCOST LOW

Looks for: a git worktree created with a name/path of .git, which git tooling then interprets as a real git directory rather than a working tree: the CVE-2026-55607 technique that abuses fsmonitor execution via symlink/path confusion. FP: low; legitimate workflows do not name a worktree .git.

// HUNT: Git worktree created with a name/path of ".git" (worktree/symlink path confusion)
// MITRE: T1036.005, T1211
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^git(\.exe)?$/i
| CommandLine=/worktree\s+add/i
| (CommandLine="*worktree add .git*" OR CommandLine="*worktree add \".git\"*" OR CommandLine="*worktree add './.git'*")
| table([ComputerName, UserName, ParentBaseFileName, GrandparentBaseFileName, CommandLine], limit=200)
Q7 · Outbound network connection from a shell descended from git
CONF MEDFP HIGHCOST MED

Looks for: a shell or scripting interpreter descended from git that also makes an outbound connection off the internal network: staging a second-stage payload after the RCE moment. FP: high: this correlates by host, not by exact process, so any unrelated outbound traffic from the host in the same window will match; narrow the window and exclude known-good destinations before trusting hit volume.

// HUNT: Outbound network connection from a shell/interpreter descended from git (post-RCE staging/C2)
// MITRE: T1105, T1071
// CONF: medium  FP: high  COST: medium | REQUIRES: ProcessRollup2, NetworkConnectIP4
// FALSE POSITIVES: host-level correlation, not process-level -- any unrelated outbound traffic in the same window will match
// TUNING: run over a narrow window (console time picker, 15-30 min); exclude allow-listed corporate-egress destinations by RemoteAddressIP4
// LOOKBACK: run over 15-30m, not the default -- see TUNING
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^(cmd|powershell|pwsh)\.exe$|^(sh|bash|zsh|dash|osascript|python3?|perl|ruby|node|curl|wget)$/i
| ParentBaseFileName=/^git(\.exe)?$/i OR GrandparentBaseFileName=/^git(\.exe)?$/i
| join(query={
    #event_simpleName=NetworkConnectIP4
    | !cidr(RemoteAddressIP4, subnet="10.0.0.0/8")
    | !cidr(RemoteAddressIP4, subnet="172.16.0.0/12")
    | !cidr(RemoteAddressIP4, subnet="192.168.0.0/16")
    | !cidr(RemoteAddressIP4, subnet="127.0.0.0/8")
    | table([aid, RemoteAddressIP4, RemotePort])
  }, field=aid, include=[RemoteAddressIP4, RemotePort], mode=inner)
| table([ComputerName, UserName, FileName, ParentBaseFileName, GrandparentBaseFileName, CommandLine, RemoteAddressIP4, RemotePort], limit=200)
Q8 · Shell-profile / dotfile persistence (macOS / Linux)
CONF HIGHFP LOWCOST LOW

Looks for: a process descended from git or an AI coding agent that references a shell profile / dotfile on its command line: the exact technique the public CVE-2026-55607 writeup describes (overwriting ~/.zshenv) to gain persistence and code execution outside the sandbox. FP: low; legitimate dotfile edits by these ancestry chains are rare.

// HUNT: Shell-profile / dotfile modification by a process descended from git or an AI coding agent
// MITRE: T1546.004
// CONF: high  FP: low  COST: low | REQUIRES: ProcessRollup2, SyntheticProcessRollup2
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| (ParentBaseFileName=/^git(\.exe)?$/i OR GrandparentBaseFileName=/^git(\.exe)?$/i OR GrandparentBaseFileName=/^(claude|claude-code|node|codex|cursor|goose|hermes|qwen-code|grok-build)(\.exe)?$/i)
| (CommandLine="*.zshenv*" OR CommandLine="*.zshrc*" OR CommandLine="*.zprofile*" OR CommandLine="*.bash_profile*" OR CommandLine="*.bashrc*" OR CommandLine="*.profile*")
| table([ComputerName, UserName, ParentBaseFileName, GrandparentBaseFileName, FileName, CommandLine], limit=200)
Q9 · Windows Run-key / scheduled-task persistence near a git-ancestry process
CONF MEDFP MEDCOST MED

Looks for: a registry Run-key/Asep value or scheduled task created on the same host, in the same narrow window, as a process descended from git: the Windows persistence parallel to Q8. FP: medium; installers and legitimate software updates create Run keys and tasks constantly, so this must be scoped tightly. ⚠ validate in tenant: parent-process linkage on Asep/registry events varies by sensor version; this query correlates by host and time window, not a direct process-id join.

// HUNT: Registry Run-key or scheduled-task persistence created shortly after a suspicious git-ancestry process
// MITRE: T1547.001, T1053.005
// CONF: medium  FP: medium  COST: medium | REQUIRES: AsepValueUpdate or RegGenericValueUpdate, ScheduledTaskRegistered, ProcessRollup2
// FALSE POSITIVES: legitimate installers and software updates create Run keys/scheduled tasks constantly
// TUNING: run over a narrow window (console time picker, 15-30 min); exclude known installer/update ComputerName groups (e.g. patch-management windows)
// LOOKBACK: run over 15-30m, not the default -- see TUNING
// NOTE: AsepValueUpdate/RegGenericValueUpdate field availability is sensor-version dependent -- validate in your tenant before deploying as a Detect IOA
#event_simpleName=/AsepValueUpdate|RegGenericValueUpdate|ScheduledTaskRegistered/
| join(query={
    #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
    | ParentBaseFileName=/^git(\.exe)?$/i OR GrandparentBaseFileName=/^git(\.exe)?$/i
    | rename(field=CommandLine, as=GitAncestryCommandLine)
    | table([aid, GitAncestryCommandLine])
  }, field=aid, include=[GitAncestryCommandLine], mode=inner)
| table([ComputerName, UserName, RegObjectName, RegStringValue, TaskName, TaskExecutable, GitAncestryCommandLine], limit=200)
09

CrowdStrike Custom IOA Recommendations

IOA NamePatternExclusionsDeployment
GitSpawn Execution ChainProcess · agent-binary grandparent → git parent → shell/interpreter childKnown internal git hooks, editor git integrationsDetect → promote from Q1 after a benign-baseline pass
Git Non-Helper ChildProcess · git parent spawning curl/wget/LOLBin, excluding known git helpersCredential-manager/askpass helpersDetect from Q2 after tuning the exclusion list
Worktree Path ConfusionProcess · git CommandLine worktree add .gitNone recommendedPrevent/Detect: high confidence (Q6)
Post-Git Credential AccessProcess · descendant of git touching SSH keys/cloud creds/netrcNone recommendedDetect (high severity) from Q5
Post-Git Dotfile RewriteProcess · descendant of git/agent referencing shell profile filesNone recommendedDetect from Q8

Q3, Q4, Q7, and Q9 are best run as scheduled searches / investigate-only, not endpoint Prevent IOAs: Q3 matches the vendor's own recommended mitigation command, and Q4/Q7/Q9 use host-level time-window correlation that needs a tenant-specific tuning pass before it can safely block.

L1 triage checklist (for a Q1/Q2/Q6 hit)

  1. Confirm the AI coding agent's installed version against the affected/fixed table in §4: is this endpoint actually running a vulnerable build?
  2. Pull the full command line and working directory of the flagged git process; identify the repository path.
  3. If the repository is reachable, inspect its .git/config and .gitattributes for core.fsmonitor, core.hooksPath, attr.tree, or filter commands (§7).
  4. Identify how the repository arrived: git log/reflog will show no clone history for a files-delivered repo; check Downloads, sync-folder, or USB provenance.
  5. Check the flagged host for Q5 (credential access), Q7 (outbound connections), Q8/Q9 (persistence) hits in the same window.
  6. If the helper program executed, treat the endpoint as compromised: rotate any credentials the logged-in user could reach (SSH keys, cloud tokens, git-credential store, saved API tokens).
  7. Isolate the host via Falcon RTR pending investigation; preserve the offending repository folder for analysis rather than deleting it.
  8. Patch/upgrade the agent to a fixed version (§12) before returning the host to service.

Pivot queries

  • Host-scoped: re-run Q1, Q5, Q7, Q8, Q9 filtered to the single flagged aid over the preceding 24h to reconstruct the full session.
  • Environment-wide: re-run Q4 (archive-extraction → git/agent) across all developer endpoints for the prior 7 days to check for other deliveries of the same repository.
10

Machine-Readable IOC Appendix

No atomic infrastructure IOCs are published for GitSpawn, so the Falcon IOC-Management block below uses REPLACE_WITH_* placeholders: populate only from confirmed incident evidence (a recovered helper binary, observed C2). The behavioral, config-key, and version-audit blocks are the operative content for this pack.

Falcon IOC Management CSVplaceholders: populate from incident only
type,value,action,severity,expiration,description,tags
sha256,REPLACE_WITH_HELPER_BINARY_HASH,detect,high,2027-03-25,GitSpawn fsmonitor/hooksPath helper (confirm in incident),campaign:GitSpawn
domain,REPLACE_WITH_C2_DOMAIN,detect,high,2026-12-25,GitSpawn post-exploit C2 (confirm in incident),campaign:GitSpawn
ipv4,REPLACE_WITH_C2_IP,detect,high,2026-12-25,GitSpawn post-exploit callback (confirm in incident),campaign:GitSpawn
# NOTE: no atomic infrastructure IOCs were published for GitSpawn -- do NOT import blank rows.
# ACTION COLUMN: every row ships at "detect", matching the Section 4 action vocabulary.
#   A hash you recovered from your own confirmed incident is the only row worth raising to
#   "prevent", and only after you have verified the binary is not a renamed legitimate tool.
#   Never raise the domain or ipv4 rows to "prevent" on one observation: post-exploit
#   callbacks land on shared and reassigned hosting, so a prevent-mode block there can cut
#   legitimate traffic. No gate downstream re-checks this column, so it is yours to own.
Behavioral signaturesthe real indicators
# GitSpawn behavioral indicators
# 1. AI coding agent binary as grandparent of git, which is parent of a shell/interpreter
# 2. git spawning a child that is not one of its documented helper binaries
# 3. git invoked with an explicit "-c core.fsmonitor=" / "-c core.hooksPath=" / "-c attr.tree=" override
# 4. Archive-extraction tool run immediately before a git/agent process launch, same host
# 5. Process descended from git touching SSH keys, cloud credential files, or git-credential stores
# 6. git worktree created named/pathed ".git" (path-confusion, CVE-2026-55607-class)
# 7. Outbound network connection from a shell/interpreter descended from git
# 8. Shell-profile/dotfile (.zshenv, .bash_profile, .profile) rewritten by a git/agent-descended process
Dangerous .git/config keysinspect any received repo
# Settings a repository's own .git/config can weaponize (GitSpawn sinks):
core.fsmonitor      # names a helper git runs automatically on every index refresh
core.hooksPath       # redirects git's hook directory to an attacker-controlled path
attr.tree             # names a tree-ish used to resolve .gitattributes -- can be abused
                      # in combination with clean/process/smudge filter commands
filter.<name>.clean   # arbitrary command run by "git add" for matching paths
filter.<name>.process # arbitrary long-running command run by git for matching paths
# Presence of ANY of these naming an executable/script in a received repo = hold and review.
Agent version / config auditrun fleet-wide
# Per-endpoint audit: is the installed agent version fixed for GitSpawn?
claude --version      # need 2.1.196+ (fsmonitor path) AND 2.1.163+ (CVE-2026-55607, worktree)
codex --version        # need 0.131.0+ (CLI) / 26.519.22136+ (macOS) / 26.519.21041+ (Windows)
goose --version         # need 1.44.0+ (CVE-2026-72718)
cursor --version         # confirm patched build per vendor release notes (no version disclosed publicly)
qwen-code --version       # UNPATCHED at publication -- treat as vulnerable regardless of version
grok-build --version       # UNPATCHED at publication -- treat as vulnerable regardless of version
hermes-agent --version      # UNPATCHED at publication -- treat as vulnerable regardless of version
# Any repo-inspection command from the "grab-keys" block above should run before opening
# a received (non-cloned) folder in any of the above, especially the still-unpatched agents.
11

Detection Validation Gates

GateCheckPass Criteria
Telemetry readyProcessRollup2/SyntheticProcessRollup2 flowing from all developer-endpoint platforms (Windows/macOS/Linux); NetworkConnectIP4 presentAll three platforms represented in a 24h sample; EDR latency < 5 min
Agent inventory readyFleet-wide agent/version audit (§10 grab-audit) completed and mapped to §4's affected/fixed tableEvery developer endpoint's agent + version documented
Benign baselineRun Q1/Q2 over a known-clean week; catalog legitimate hook/editor-integration ancestry chainsFP set documented and added to each query's exclusion list
Positive testQ1/Q6/Q8 fire on a lab host running a benign script that reproduces the exact ancestry shape (agent-launched shell under git; a worktree literally named test-dot-git; a dotfile edit under a git-descended shell): never a functional fsmonitor payloadEach query returns the seeded activity
PromotionQ1, Q2, Q6, Q5, Q8 → Detect IOA after baseline; Q3/Q4/Q7/Q9 stay scheduled-search/investigate-onlyPromoted with documented exclusions per §9
12

Hardening: Tiered

Immediate (this week)
  • Disable the fsmonitor sink globally on every developer endpoint: git config --global core.fsmonitor false: until every AI coding agent in use is confirmed on a fixed build. (MITRE M1042 Disable or Remove Feature or Program · Manifold/The Hacker News vendor mitigation guidance)
  • Version-pin and upgrade every affected agent to the fixed builds in §4/§10 (Claude Code 2.1.196+ and 2.1.163+, Codex CLI 0.131.0+, Goose 1.44.0+); treat Hermes Agent, Qwen Code, and Grok Build as unpatched regardless of version until vendor fixes ship. (MITRE M1051 Update Software · CVE-2026-19592 / CVE-2026-72718 / CVE-2026-55607 fix records)
  • Instruct developers to inspect .git/config before opening any repository received as files (zip, cloud-drive share, USB, "bug report" archive): never a normal clone/fetch/pull: using the audit commands in §7/§10. (MITRE M1017 User Training · ⚠ best-practice, no formal benchmark)
Near term (1–4 weeks)
  • Deploy Q1/Q2/Q6 as scheduled searches (promoting to Detect IOAs after the benign-baseline pass in §11) so the execution chain is caught even if an agent is missed during the version-pin rollout. (MITRE M1040 Behavior Prevention on Endpoint)
  • Route archive/zip handoffs (contractor deliverables, "bug report" attachments) through a scan-and-quarantine step that flags any archive containing a .git directory for manual config review before it reaches a developer's agent. (MITRE M1038 Execution Prevention · ⚠ best-practice, no formal benchmark)
  • Set safe.directory scoping so git does not implicitly trust arbitrary extracted/synced folders, reducing the surface that silently triggers background context-gathering commands. (MITRE M1042 · git-scm.com safe.directory documentation)
Strategic (1–3 months)
  • Standardize on agent versions via a managed software catalog with automatic update enforcement for AI coding agents, closing the "which build is actually installed" gap that made this class of bug persist across releases. (MITRE M1051 · CIS Control 2: Inventory and Control of Software Assets)
  • Application allowlisting / execution control on developer endpoints for the helper-program shape this bug abuses: an unsigned or unexpected binary/script launched as a child of git should require explicit approval. (MITRE M1038 · NIST SP 800-167 Application Whitelisting)
  • Sandbox or VM-isolate first-time-seen repositories (contractor handoffs, external contributions received as files) before opening them in any AI coding agent, so a live fsmonitor/hooksPath payload cannot reach the primary developer identity/credential set even if it fires. (MITRE M1048 Application Isolation and Sandboxing · NIST SP 800-207 Zero Trust Architecture)
13

Deployable Playbooks

Playbook A: Disable the fsmonitor sink fleet-wide (Windows / macOS / Linux, shell)

Prerequisites: git 2.x installed; ability to push a global gitconfig change via RMM/MDM/Ansible to developer endpoints. Reboot required: none. Rollback: re-enable with git config --global core.fsmonitor true (or remove the line from the global gitconfig) once every agent in the fleet is confirmed patched.

# 1. Push to every developer endpoint's per-user git global config
git config --global core.fsmonitor false

# 2. Verify it took effect
git config --get core.fsmonitor
# expect: false

# 3. (Optional, stronger) also neutralize the other reported sinks globally where supported by your git version:
git config --global core.hooksPath ""
# Rollback: git config --global --unset core.fsmonitor
#           git config --global --unset core.hooksPath

Playbook B: Version-pin and upgrade affected agents

Prerequisites: package-manager or installer access for each agent (npm/pip/brew/winget/direct installer); a maintenance window is not required since these are user-space CLI tools, but active agent sessions should be closed first. Reboot required: none for CLI agents; Codex Desktop / Cursor (Electron apps) require the application to restart, not the OS. Rollback: pin back to the prior version only if the upgrade breaks a workflow: re-exposes the vulnerability, so pair any rollback with Playbook A staying active.

# Claude Code -- confirm BOTH fixes are present (they are different bugs):
npm install -g @anthropic-ai/claude-code@latest   # need >=2.1.196 AND >=2.1.163
claude --version

# OpenAI Codex CLI -- need >=0.131.0
npm install -g @openai/codex@latest
codex --version

# Goose -- need >=1.44.0
# (use your platform's Goose install/update mechanism; verify via)
goose --version

# Unpatched at publication -- Hermes Agent, Qwen Code, Grok Build:
# no fixed version exists yet. Apply Playbook A (disable core.fsmonitor) and
# Playbook C (repo intake review) as compensating controls until a fix ships.
# Rollback: revert to the previously pinned package version via your package
# manager's install-specific-version syntax if the new build breaks a workflow.

Playbook C: Repository intake review (any platform received as files, not cloned)

Prerequisites: none beyond a shell and git itself; suitable for a pre-commit-style local script or a SOAR/EDR RTR script triggered on archive extraction. Reboot required: none. Rollback: none required: this is a read-only inspection step with no persistent system change.

#!/usr/bin/env bash
# Run against any repository that arrived as a zip/tar/synced-folder/USB copy
# (never needed for a plain "git clone" -- that path cannot carry these settings).
REPO_DIR="$1"
cd "$REPO_DIR" || exit 1
echo "== Checking $REPO_DIR/.git/config and .gitattributes for named-program sinks =="
grep -nE "fsmonitor|hooksPath|\[filter" .git/config .gitattributes 2>/dev/null
if [ $? -eq 0 ]; then
  echo "HOLD: this repo's config names an external program -- review before opening in any AI coding agent."
  exit 1
fi
echo "No known GitSpawn sink strings found. Still confirm agent version against Section 4/10 before proceeding."

Playbook D: Safe-directory scoping (git >=2.35.2, all platforms)

Prerequisites: git version supporting safe.directory (2.35.2+, effectively all currently-supported git releases). Reboot required: none. Rollback: git config --global --unset-all safe.directory restores git's prior implicit-trust behavior.

# Scope trust to explicitly-approved project roots instead of trusting every
# directory git is pointed at (reduces the set of folders where an agent's
# background git command will silently operate on an unreviewed .git/config):
git config --global --add safe.directory /Users/*/projects/*
git config --global --add safe.directory C:/Users/*/source/*
# Verify:
git config --get-all safe.directory
# Rollback: git config --global --unset-all safe.directory
14

Containment Runbook

PhaseActionsOwnerEvidence
IsolateNetwork-contain the flagged host via Falcon RTR; suspend the offending AI-agent process tree without deleting the source repository folderSOC / EDRContainment event; process tree snapshot
EradicateKill the helper-program process tree; preserve (do not delete) the malicious repository's .git/config and .gitattributes for analysis; upgrade the agent to a fixed build (§12/§13B); apply core.fsmonitor=false fleet-wide if not already (§13A)Platform / SOCPreserved config file copy; agent version post-upgrade; git-config audit output
RecoverRotate SSH keys, cloud CLI credentials, npm/git-credential tokens, and any API tokens reachable by the logged-in user on the affected host; re-run Q5/Q8/Q9 to confirm no residual credential access or persistenceIAM / SOCCredential-rotation record; clean re-run of Q5/Q8/Q9
MonitorRun Q1–Q9 as scheduled searches for 30 days across all developer endpoints; watch for repeat delivery of the same or a similarly-crafted repositorySOCScheduled-search results; repeat-offender tracking
15

Detection Coverage Map

TechniqueBehaviorCQLIOACoverage
T1195 / T1059 GitSpawn execution chainAgent → git → shell/interpreterQ1Sched. search → DetectGood
T1059 / T1105 Non-helper git childgit spawns non-helper binaryQ2DetectGood
T1059 Config override on command lineExplicit -c core.fsmonitor=/hooksPath/attr.treeQ3:Partial: also matches the benign vendor mitigation
T1204.002 / T1027 Delivery via archiveExtraction → git/agent launchQ4:Partial: host-level correlation, high FP without tuning
T1552.001 / .004 Credential accessGit-descended process reads SSH/cloud credsQ5DetectGood
T1036.005 / T1211 Worktree path confusionWorktree named/pathed .gitQ6Prevent/DetectGood
T1105 / T1071 Post-RCE staging/C2Outbound from a git-descended shellQ7:Partial: host-level correlation, high FP without tuning
T1546.004 Dotfile persistence (macOS/Linux)Shell-profile rewrite by git/agent descendantQ8DetectGood
T1547.001 / T1053.005 Windows persistenceRun-key/scheduled-task near git ancestryQ9:Partial: Asep/registry parent linkage is tenant/sensor-version dependent, ⚠ validate
T1195 The exploit trigger itself (git reading a malicious .git/config)fsmonitor/hooksPath/attr.tree value being read from disk::GAP: Falcon does not inspect file contents at rest; only the resulting process launch (Q1/Q2/Q3) is visible

Known gap: there is no way to detect a malicious .git/config value purely from its presence on disk with EDR telemetry: the sensor sees the process that reads it (the git launch) and the process it spawns, not the file's contents. This pack closes that gap behaviorally (§8 Q1–Q3) rather than via file-content inspection, and closes it operationally via the intake-review playbook (§13C) that DOES read the file. Validation gates for all CQL are in §11.

16

Hunt Summary Ticket

HUNT TICKET · GitSpawn · AI Coding Agent Git-Config RCE
TITLE:      GitSpawn -- AI coding agent RCE via a received repository's own .git/config
SEVERITY:   HIGH (sandbox-escape RCE, CVSS up to 8.8 across component CVEs; no confirmed ITW)
SCOPE:      All Windows/macOS/Linux developer endpoints running Claude Code, OpenAI Codex,
            Cursor, Goose, Hermes Agent, Qwen Code, or Grok Build
HYPOTHESIS: A repository received as files (zip/sync/USB, never a clone) with a malicious
            core.fsmonitor/hooksPath/attr.tree setting causes an AI coding agent's background
            git command to execute an attacker-named helper as the logged-in user, outside
            the agent sandbox, followed by credential access and/or persistence.
QUERIES:    Q1 execution chain - Q2 non-helper child - Q3 config override - Q4 archive delivery
            - Q5 credential access - Q6 worktree confusion - Q7 outbound stage/C2
            - Q8 dotfile persistence (macOS/Linux) - Q9 Run-key/task persistence (Windows)
DO FIRST:   1) Fleet-wide agent/version audit against Section 4/10; flag every endpoint
               running an unpatched build (all of Hermes Agent, Qwen Code, Grok Build
               are unpatched regardless of version)
            2) Push "git config --global core.fsmonitor false" fleet-wide (Playbook A)
            3) Run Q1/Q2/Q6 across all developer endpoints for the prior 7 days
FINDINGS:   <record execution-chain hits, credential-access hits, and any persistence found>
GAPS:       No EDR visibility into .git/config file contents -- only the resulting process
            launch is detectable. No atomic infrastructure IOCs published for this research.
ACTIONS:    Disable fsmonitor sink + version-pin/upgrade agents + repo-intake review process
            + credential rotation on any confirmed-executed host + 30-day scheduled hunt
OWNER:      HuntPack
VERSION:    v0.1 · 2026-09-25
17

Changelog

v0.12026-09-25Initial HuntPack for GitSpawn (multi-agent AI coding agent git-config RCE class). 9 behavioral CQL hunts covering the execution chain, delivery vector, credential access, CVE-2026-55607-class worktree confusion, post-RCE staging, and cross-platform (Windows/macOS/Linux) persistence. IOA recommendations, tiered hardening with deployable playbooks (Prerequisites/Reboot/Rollback per step), and a phased containment runbook. Behavioral pack -- no atomic infrastructure IOCs published for this research; the Falcon IOC Management CSV ships placeholder rows only.
18

References

TierSourceUsed ForAccess Date
PrimaryManifold Security: "GitSpawn"Original disclosure: mechanism, 8 findings/7 agents, delivery vector, mitigation language2026-09-25
NewsThe Hacker NewsPer-agent affected/fixed version table, disclosure timeline, additional sink names2026-09-25
NewsShattered.ioCorroborates patch-status table and clone-immunity framing2026-09-25
NewsByteIotaCorroborates mechanism/agent list only: two uncorroborated claims from this source were dropped, see §22026-09-25
NewsCybersecuritynews.comMechanism detail, "cannot arrive via clone/fetch/pull" delivery-reality language2026-09-25
NewsGBHackersThird corroboration of per-agent affected/fixed version numbers2026-09-25
Vendor CVEGitLab Advisory DB: CVE-2026-55607Claude Code worktree path-confusion sandbox escape: affected/fixed versions, CVSS 8.8, CWE-22/59/782026-09-25
Vendor CVEOpenCVE: CVE-2026-19592OpenAI Codex CLI/Desktop affected/fixed versions, CVSS 7.3, CWE-152026-09-25

Generated 2026-09-25 · HuntPack pipeline (web-hunter-v2 → threat-hunter-v2 → crowdstrike-logscale-v3 → alert-builder-v2 → threat-hardening-v2 → review-v2) · Defensive content only.