title: Git Configuration Turned Into an Execution Hook by an Agent
id: ATR-2026-02530
rule_version: 1
status: experimental
description: |
  Detects an agent tool call that points a git configuration callback key at an EPHEMERAL or INLINE-SHELL value. Several git config keys are not settings but callbacks -- core.fsmonitor, core.sshCommand, core.hooksPath, core.askpass, credential.helper, filter.*.clean/smudge, diff.*.textconv, uploadpack.packObjectsHook. Once one of them holds a command, that command runs on the NEXT ORDINARY GIT OPERATION: a status, a diff, a fetch. No further tool call is needed and nothing in the later invocation looks dangerous.
  Derived from CVE-2026-55607 (Claude Code 2.1.38 to 2.1.163), where worktree handling permitted a worktree named ".git" plus navigation outside the sandbox context, and git fsmonitor execution during worktree operations was the step that turned a directory-confusion trick into code execution outside the seatbelt sandbox. The advisory states that reliable exploitation required the user to clone a malicious repository containing prompt injection content -- so the config write arrives as an agent action taken on behalf of injected text, which is exactly what this rule reads.
  THE VALUE REQUIREMENT IS THE PRECISION, AND IT IS NOT "LOOKS LIKE A PROGRAM". An earlier draft of this rule required only that the value be a path or an interpreter. That was measured against realistic benign input and fired on 20 of 26 samples -- because a program path is the NORMAL, CORRECT value for every one of these keys. `core.editor=/usr/bin/vim`, `core.pager=/usr/bin/less`, `credential.helper=/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret` (git's own documented Linux helper), `filter.nbstripout.clean='python3 -m nbstripout'` (the standard Jupyter setup) and `core.fsmonitor=/opt/homebrew/bin/watchman` all matched. "Points at a program" is what these keys are FOR; it carries no signal at all.
  So the value must instead look like STAGED ATTACK CODE:
    - a path under an ephemeral directory (/tmp, /var/tmp, /dev/shm,
      /private/tmp, /var/folders, ~/.cache, $TMPDIR) -- where a payload dropped
      moments earlier in the same session lives, and where no package manager,
      no distro and no developer ever installs a durable git helper; or
    - an inline interpreter invocation or fetch-and-run (`sh -c`, `bash -c`,
      `python -c`, `perl -e`, `node -e`, `eval`, `base64 -d`, curl, wget, nc)
      -- a command literal rather than a reference to an installed tool.

  KEYS DELIBERATELY DROPPED, for measured reasons. core.editor, core.pager and sequence.editor were in the first draft and contradict this rule's own thesis: they do NOT run on the next ordinary git operation, they run when a human interactively commits or reads a log, in the foreground, where the user sees them. They also carry the densest benign population of any key here. Likewise mergetool.*.cmd and difftool.*.cmd fire only on explicit invocation. Removing them cost no true positive and removed nine measured false positives.
  ALSO COVERED: the one-shot `git -c key=cmd` form, and the same keys written directly into a config file body.
  NOT COVERED, deliberately, and both for measured reasons.
    - `git worktree add ./.git`, the directory-confusion half of the same CVE,
      is already detected by ATR-2026-02302 (Git Worktree Created With
      Reserved Name .git). A draft of this rule carried that condition; it was
      removed once the cross-check showed 02302 firing on it.
    - Git hook FILES (.git/hooks/pre-commit and friends) are a neighbouring
      persistence technique with a different shape and a much denser benign
      population -- husky, pre-commit and lefthook all write there. Left out
      rather than folded in badly.
author: ATR Community
date: 2026/08/23
schema_version: '0.1'
detection_tier: pattern
maturity: test
severity: high
references:
  cve:
    - CVE-2026-55607
  cwe:
    - CWE-78
    - CWE-59
  owasp_llm:
    - LLM01:2025
  owasp_agentic:
    - ASI04:2026
  mitre_atlas:
    - AML.T0051.001 - Indirect
  mitre_attack:
    - T1546 - Event Triggered Execution
compliance:
  owasp_llm:
    - id: LLM01:2025
      context: The advisory names a cloned repository carrying prompt-injection content as the precondition, so the configuration write is an injected instruction executed by the agent.
      strength: primary
  owasp_agentic:
    - id: ASI04:2026
      context: 'Persistence outside the session: the callback survives in the repository or user configuration and fires on later, unrelated git operations.'
      strength: primary
  eu_ai_act:
    - article: '15'
      context: Article 15 resilience must hold against an agent being induced to reconfigure its own execution environment so that later benign operations run attacker code.
      strength: primary
    - article: '14'
      context: A reviewer approving a later `git status` cannot see the callback installed earlier; detecting the install is what keeps oversight meaningful across turns.
      strength: secondary
    - article: '9'
      context: Environment-persistence through developer tooling is a foreseeable risk for coding agents and belongs in the risk register with continuous monitoring.
      strength: secondary
  nist_ai_rmf:
    - function: Manage
      subcategory: MG.2.3
      context: Runtime treatment for the risk that an agent installs a deferred execution callback in its own working environment.
      strength: primary
    - function: Map
      subcategory: MP.5.1
      context: 'Catalogues deferred, trigger-based execution as distinct from direct command execution: the dangerous act and the dangerous effect are separated in time.'
      strength: secondary
    - function: Measure
      subcategory: MS.2.7
      context: Detection events supply the security evidence for the agent's control over its own toolchain configuration.
      strength: secondary
  iso_42001:
    - clause: '8.1'
      context: Operational control over an AI system with developer tooling access requires that the system cannot silently arm its environment to execute later.
      strength: primary
    - clause: '8.4'
      context: Impact assessment for a coding agent must include sandbox escape by environment reconfiguration; these detections are the supporting evidence.
      strength: secondary
    - clause: '6.2'
      context: Preventing persistent, deferred code execution installed by the agent is an AIMS security objective, operationalised here as a runtime detection.
      strength: secondary
tags:
  category: privilege-escalation
  subcategory: vcs-config-execution-hook
  scan_target: both
  confidence: medium
  suppress_in_code_blocks: true
agent_source:
  type: tool_call
  framework:
    - any
  provider:
    - any
detection:
  condition: any
  conditions:
    - field: tool_args
      operator: regex
      value: (?i)(?:^|[^\x60])\bgit\s+(?:-[a-zA-Z]\s+\S{1,40}\s+|--\S{1,24}\s+){0,3}config\s+(?:--\S{1,16}\s+){0,2}['\"]?(?:core\.(?:fsmonitor|sshcommand|hookspath|askpass)|credential\.helper|(?:diff|merge)\.[\w.-]{1,32}\.(?:textconv|driver)|filter\.[\w.-]{1,32}\.(?:clean|smudge|process)|uploadpack\.packobjectshook)['\"]?\s*[= ]\s*['\"]?\s*(?:(?:/private)?/(?:tmp|var/tmp|dev/shm)/|\b(?:sh|bash|zsh|dash)\b\s{1,4}-c|\b(?:python[23]?|perl|ruby|node)\b\s{1,4}-[ce]\b|\b(?:curl|wget|eval|nc)\s)
      description: A git callback key is set to a staged payload path or an inline interpreter command, arming code that runs on the next ordinary git operation
    - field: tool_args
      operator: regex
      value: (?i)(?:^|[^\x60])\bgit\s+-c\s+['\"]?(?:core\.(?:fsmonitor|sshcommand|hookspath|askpass)|credential\.helper|(?:diff|merge)\.[\w.-]{1,32}\.(?:textconv|driver)|filter\.[\w.-]{1,32}\.(?:clean|smudge))\s*=\s*['\"]?\s*(?:(?:/private)?/(?:tmp|var/tmp|dev/shm)/|\b(?:sh|bash|zsh|dash)\b\s{1,4}-c|\b(?:python[23]?|perl|ruby|node)\b\s{1,4}-[ce]\b|\b(?:curl|wget|eval|nc)\s)
      description: The one-shot -c form arms the same callback for the duration of a single git invocation, leaving no persistent config entry to review
    - field: tool_args
      operator: regex
      value: (?i)\[(?:core|filter\s+\"[^\"\]]{1,32}\"|diff\s+\"[^\"\]]{1,32}\")\][\s\S]{0,120}\b(?:fsmonitor|sshcommand|hookspath|askpass|textconv|packobjectshook|clean|smudge)\s*=\s*['\"]?\s*(?:(?:/private)?/(?:tmp|var/tmp|dev/shm)/|\b(?:sh|bash|zsh|dash)\b\s{1,4}-c|\b(?:python[23]?|perl|ruby|node)\b\s{1,4}-[ce]\b|\b(?:curl|wget|eval|nc)\s)
      description: A git config file is written with a callback key pointing at a staged payload or inline shell, bypassing the git config command entirely
  false_positives:
    - CI that legitimately stages an ssh wrapper or askpass helper in a temp directory for the life of one job, e.g. `git config core.sshCommand /tmp/ssh-wrap.sh`. This is genuinely the same shape as the attack and is expected to match; the ephemeral location is the whole signal and cannot distinguish a friendly script from a hostile one
    - 'Security documentation that quotes the arming command as BARE PROSE with no backticks and no fence, e.g. a SECURITY.md paragraph written through a write_file tool call. Measured residue: code-block suppression catches the backticked and fenced forms, which is how documentation is written the overwhelming majority of the time, but unformatted prose still matches'
    - A durable helper deliberately installed under /var/tmp, which is a temp root but survives reboot. Pointing a git callback there is anomalous regardless of intent, so it matches
    - A repository bootstrap script that fetches a filter helper with curl and wires it into filter.*.clean in the same command
response:
  actions:
    - alert
    - escalate
  actions_rationale: 'response-action eligibility (docs/RESPONSE-ACTION-ELIGIBILITY.md): no FP measurement on the benign corpus; ceiling = observe. Removed block_tool(interrupt). Detection unchanged — recall cost is zero.'
  auto_response_threshold: high
  message_template: |
    [ATR-2026-02530] A git configuration callback key was pointed at a program. It will execute on the next ordinary git operation, not on this tool call (CVE-2026-55607 shape). Inspect the repository this agent was working in before allowing further git commands.
confidence: 70
