CVE-2026-110860
Executive Summary
CVE-2026-110860 is a symlink-following vulnerability in GitPython versions 3.1.62 through 3.1.x, specifically within the Submodule.move() method, which performs only lexical destination validation and fails to reject symbolic links in intermediate path components. An attacker-controlled repository can commit a symlink pointing outside the worktree, causing any application that moves an initialized submodule beneath that symlink to relocate the checkout externally, corrupting the index and .gitmodules. With a CVSS score of 6.1 and no public exploit or patch available, organizations using GitPython for automated repository operations should treat this as a supply chain integrity risk.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
GitPython is a Python library for interacting with Git repositories programmatically. The vulnerability resides in Submodule.move(), a method intended to relocate an initialized submodule from one path to another within the worktree. The method validates the destination path using lexical checks only — meaning it evaluates the string representation of the path without resolving filesystem-level indirection such as symbolic links.
The core flaw is a classic CWE-59 (Improper Link Resolution Before File Access) issue: path components that are symlinks are not detected or rejected. When an untrusted repository commits a symlink (for example, a directory entry named vendor) that points outside the worktree, and an application later calls Submodule.move() to relocate a submodule beneath that path, GitPython follows the symlink. The submodule checkout is consequently written to a location outside the intended working directory.
This has two immediate consequences:
- Path traversal via symlink: The destination is no longer bounded by the worktree root, enabling writes to attacker-influenced locations on the filesystem accessible to the process.
- Repository metadata corruption: The Git index and
.gitmodulesfile are updated to reflect the move, but because the physical checkout now resides elsewhere, the repository state becomes inconsistent. Subsequent Git operations may fail or behave unpredictably.
The attack surface is any application that clones or interacts with untrusted repositories and programmatically manages submodules — CI/CD pipelines, dependency automation tools, repository migration utilities, and similar automated Git workflows. The CVSS vector (AV:L, AC:L, PR:N, UI:R, S:U, C:N, I:H, A:L) indicates local attack vector, low complexity, no privileges required, but user interaction is required (a maintainer or automated process must initiate the move operation). Integrity impact is high, availability impact is low, and confidentiality impact is none.
Exploitation Scenarios
Reconnaissance/target identification: An attacker identifies a target application or CI/CD pipeline that processes untrusted Git repositories and uses GitPython's submodule management APIs, particularly
Submodule.move(). The attacker creates or compromises a repository containing a malicious symlink in the path where a submodule is expected to be moved.Triggering the flaw class: The victim application initializes a submodule and then invokes
Submodule.move()to relocate it. GitPython's lexical validation of the destination path does not resolve or reject the committed symlink component. Because the symlink is not detected, the move operation proceeds.Payload/execution method: At the vulnerability-class level, this is a symlink-following path traversal. The attacker's committed symlink causes the submodule checkout to be written outside the worktree. No code execution payload is inherent to the flaw; the impact is unauthorized filesystem writes and repository metadata corruption. The attacker may use the out-of-bounds write to place files in locations that influence subsequent build steps or runtime behavior, depending on the consuming application.
Post-exploitation impact: The Git index and
.gitmodulesare corrupted, leading to inconsistent repository state. Depending on the application's behavior, this can cause build failures, dependency confusion, or the introduction of attacker-controlled files into build artifacts or deployment packages. No public PoC is available; the attack chain is inferred from the vulnerability class and the NVD description.
Impact Assessment
The CVSS 3.1 score of 6.1 reflects a medium-severity vulnerability. The integrity impact is rated High because the submodule checkout can be relocated outside the worktree and repository metadata (index, .gitmodules) is corrupted. Availability impact is Low due to potential repository operation failures. Confidentiality impact is None, as the flaw does not directly expose data.
Business impact includes:
- Supply chain integrity: Corruption of submodule references can introduce unauthorized content into build pipelines or deployment artifacts.
- CI/CD disruption: Automated pipelines relying on GitPython for submodule management may fail or produce inconsistent states.
- Blast radius: Any environment where GitPython is used to process untrusted repositories — including build servers, dependency bots, and repository migration tools — is potentially affected. The local attack vector limits remote exploitation, but the user interaction requirement is often satisfied automatically in CI/CD contexts.
Detection Guidance
Sigma Rule
title: GitPython Submodule Move Symlink Following Attempt
id: 8f4b2c1e-3a7d-4e5f-9b2a-1c6d8e9f0a3b
status: experimental
description: Detects process command lines or file operations consistent with GitPython submodule move operations involving symlinked paths
author: Threat Intelligence
date: 2026-01-01
logsource:
category: process_creation
product: linux
detection:
selection:
Image|endswith:
- '/python'
- '/python3'
CommandLine|contains:
- 'gitpython'
- 'Submodule'
- 'move'
condition: selection
falsepositives:
- Legitimate GitPython submodule management in trusted repositories
level: medium
tags:
- attack.t1195
- cve.2026.110860
YARA Rule
rule CVE_2026_110860_GitPython_Submodule_Symlink
{
meta:
description = "Detects GitPython versions 3.1.62 to 3.1.x with vulnerable Submodule.move()"
author = "Threat Intelligence"
date = "2026-01-01"
reference = "CVE-2026-110860"
severity = "medium"
strings:
$gitpython_version = /3\.1\.(6[2-9]|[7-9][0-9])/
$submodule_move = "Submodule.move"
$symlink_check = "islink"
condition:
$submodule_move and $gitpython_version and not $symlink_check
}
Suricata IDS Rule
alert tcp any any -> any any (msg:"CVE-2026-110860 GitPython Submodule.move Symlink Following Attempt"; flow:to_server,established; content:"Submodule"; content:"move"; distance:0; content:".gitmodules"; distance:0; sid:2026110860; rev:1; metadata:created_at 2026_01_01, cve CVE-2026-110860; classtype:attempted-user;)
Elastic Detection
process where process.name in ("python", "python3") and
process.command_line : "*Submodule*" and
process.command_line : "*move*" and
process.command_line : "*.gitmodules*"
Splunk SPL Query
index=main sourcetype=linux_audit OR sourcetype=sysmon
| search (process_name="python" OR process_name="python3") AND (command_line="*Submodule*" AND command_line="*move*")
| stats count by host, user, process_name, command_line
| where count > 0
Wazuh OSSEC Rule
<group name="gitpython,cve-2026-110860,">
<rule id="110860" level="10">
<decoded_as>json</decoded_as>
<field name="process.name">python|python3</field>
<field name="process.command_line">Submodule.*move</field>
<description>CVE-2026-110860: GitPython Submodule.move symlink following attempt detected</description>
<mitre>
<id>T1195</id>
</mitre>
<group>supply_chain,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source).
Immediate mitigations:
- Disable or restrict automated submodule move operations on untrusted repositories.
- Audit repositories for committed symlinks in path components used during submodule operations.
- Run GitPython-based processes in sandboxed environments with restricted filesystem write access outside the worktree.
- Implement path resolution checks (e.g.,
os.path.realpath) in application code before invokingSubmodule.move().
Patch/upgrade steps:
- Monitor the GitPython project for a patched release (3.2.0 or later is implied by the version range, but no patch evidence is available from tracked sources).
- Once a patch is released, upgrade immediately and verify the fix addresses symlink resolution in
Submodule.move().
Long-term hardening:
- Adopt a policy of never processing untrusted repositories with write access to the host filesystem.
- Integrate symlink detection into repository ingestion pipelines.
- Use containerized or ephemeral build environments with read-only mounts where possible.
- Maintain an inventory of applications using GitPython and track their dependency versions.
References
- NVD — CVE-2026-110860: https://nvd.nist.gov/vuln/detail/CVE-2026-110860
- GitPython Project: https://gitpython.readthedocs.io/
- CWE-59: Improper Link Resolution Before File Access: https://cwe.mitre.org/data/definitions/59.html
- MITRE ATT&CK T1195 — Supply Chain Compromise: https://attack.mitre.org/techniques/T1195/
- CISA KEV Catalog: Not applicable (CVE-2026-110860 is not listed in CISA KEV)
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.