DEV Community

jamilxt
jamilxt

Posted on

A Git Clone Can Run Attacker Code. A Safer Workflow for Repositories with Submodules

A repository can look like data until a command asks Git to fetch every submodule. On November 10, 2026, the Git project disclosed a high-severity flaw that could let an attacker-controlled repository run code during a recursive clone. The command developers often use to get a project ready in one step can cross the boundary from downloading source to processing attacker-controlled configuration and hooks.

The fix is not to stop using Git or to treat every public repository as malicious. It is to update Git, find the automated systems that clone repositories on your behalf, and stop making recursive cloning an unexamined default for untrusted sources.

This article turns the disclosure into a practical workflow for individual developers and teams. It does not demonstrate the exploit. The focus is on how to reduce exposure and verify that the systems which process repositories are using patched Git.

What the Git flaw does, and what it does not mean

The vulnerability is tracked as CVE-2026-111760. GitHub's technical explanation says Git validates paths before writing them, but an integer truncation in index handling could let an extremely long path pass validation under one name and later be written under a shorter name. An attacker could use that difference to replace a submodule's .git file with a symbolic link to a directory containing malicious configuration or hooks. Git could then execute attacker-controlled code during a recursive clone.

The relevant trigger is important: the Git project said the issue was believed to be triggerable when --recurse-submodules is used. This is not a claim that merely reading any repository page in a browser runs code, nor that every clone is automatically exploitable. The project's recommended precaution is to avoid recursive clones of untrusted repositories and clone only from trusted servers if you cannot update immediately.

Git's November 10 release announcement covers six security issues, not only this one. The other issues involve reference path traversal, stack or heap corruption, out-of-bounds reads while applying binary patches, and unsafe file access through fast-import streams. That wider scope matters: removing --recurse-submodules is a temporary mitigation for one attack path, not a substitute for upgrading Git.

Step 1: Find every Git that actually runs

Start by checking the Git in your interactive shell:

git --version
Enter fullscreen mode Exit fullscreen mode

The release announcement lists Git 2.56.1 and maintenance releases 2.55.1, 2.54.1, 2.53.1, 2.52.1, 2.51.3, and 2.50.2 as containing fixes. The Git v2.56.1 release notes are the project's version-specific record. One detail is easy to miss: the separate CVE advisory page still says “Patched versions: none” and “Patches are being discussed,” even though the Git project's November 10 release announcement lists fixed versions. That appears to be an advisory-page update lag; use the release announcement and release notes for the fix list, and check your distributor for package availability. Install the patched version offered by your operating system or Git distributor. Do not assume that updating the package on your laptop updates every Git binary used by your organization.

Check the places where repository operations happen:

  • Developer laptops and remote development environments.
  • CI runners, build agents, and self-hosted automation workers.
  • Containers and VM images used for builds.
  • IDEs, desktop Git clients, and coding-agent applications that bundle Git.
  • Services that mirror, import, merge, or inspect repositories for other users.

GitHub's release note specifically calls out applications that bundle Git, and its announcement says patched versions of GitHub Desktop, the Copilot app, Codespaces, and Actions were being coordinated or deployed. Those statements describe GitHub's products at announcement time; they are not a guarantee about every installed client or runner. Check each product's current update status rather than inferring it from the command-line Git version.

For a CI runner, log the version from the same job image and execution context that performs the checkout. Running git --version on an administrator's laptop does not verify the binary in a container image or hosted runner. Record the version in build output, then rebuild or update pinned images and worker templates so new jobs inherit the patched package.

Step 2: Map recursive submodule use

Search pipeline definitions, scripts, and build configuration for recursive checkout behavior. Common forms include:

git clone --recurse-submodules <repository>
git submodule update --init --recursive
Enter fullscreen mode Exit fullscreen mode

Also inspect CI actions and checkout plugins for a setting that recursively initializes submodules. The command may not appear literally in the repository: an action, wrapper, or build service can invoke it on behalf of the project.

Classify each use by trust boundary:

  • Repositories controlled by your team: still update Git, but a controlled source may be treated differently from an unknown contribution.
  • Third-party dependencies and templates: verify ownership and the source before allowing automation to fetch nested repositories.
  • Forks, pull requests, and user-submitted repositories: treat them as untrusted input, especially on self-hosted runners that have access to credentials or internal networks.
  • Public CI examples copied into a build: review what the automation does, not only what the visible YAML appears to say.

Do not confuse a repository host with trust in every repository on that host. The advisory describes an attacker-controlled repository hosted by the attacker, while the broader lesson is to make the source and automation boundary explicit. A familiar domain name alone does not establish that a contributor's repository is safe to process with privileged credentials.

Step 3: Use a cautious inspection flow for untrusted projects

If you cannot patch Git immediately and need to inspect an untrusted repository, do not use recursive submodule cloning. Start with the vendor's temporary precaution: clone from a source you have a reason to trust, and avoid --recurse-submodules for untrusted repositories.

For example, a basic clone without recursive initialization is:

git clone <repository>
Enter fullscreen mode Exit fullscreen mode

This avoids the specific recursive-clone trigger described for CVE-2026-111760, but it should not be presented as a universal sandbox. The November release fixes several distinct issues, and other tools may process repository contents in additional ways. Do not run build scripts, package installation, Git hooks, or project-specific automation from an untrusted checkout merely because the first clone completed.

Before initializing submodules, inspect the repository's .gitmodules file and the project's documentation. The file lists submodule paths and URLs; use it to understand which additional repositories the checkout would introduce. Then verify that each source is expected and maintained by an identity you trust. Inspection is a decision aid, not proof that a repository is harmless. If you cannot validate the source, leave the submodules uninitialized until you can use a patched Git in an isolated environment.

Step 4: Reduce the damage a CI checkout can cause

Patching is the primary fix. Isolation is the layer that limits consequences if a future parser or repository-processing flaw appears.

For pull requests from forks or other untrusted sources:

  • Prefer ephemeral runners that are destroyed after the job, rather than long-lived workers containing old workspaces or credentials.
  • Do not expose deployment secrets or broad repository write tokens to jobs that only need to compile or test proposed code.
  • Keep the runner's network access narrow where practical, especially for internal services that the job does not need.
  • Separate checkout and build permissions from release and deployment permissions.
  • Make submodule fetching explicit, and enable it only for workflows and sources that require it.
  • Rebuild runner images from patched operating-system packages, then confirm the runtime version in the job log.

These are general containment controls, not a claim that the Git advisory requires one particular CI architecture. The right permissions depend on what a job needs. The useful question is simple: if repository processing executes code, what can that process read, change, or reach?

A short response checklist

Save this for the next repository or runner review:

  1. Patch: Confirm the Git version in the actual environment that clones or processes the repository, including bundled copies.
  2. Inventory: Find recursive submodule initialization in scripts, CI settings, IDEs, and wrappers.
  3. Classify: Separate team-controlled repositories from forks, public contributions, and unknown sources.
  4. Constrain: Do not recursively clone untrusted repositories with an unpatched Git. Keep untrusted CI jobs away from secrets and persistent privileged workers.
  5. Verify: Rebuild images and templates, rerun a representative job, and capture its Git version in logs.
  6. Review the other fixes: If automation applies binary patches, merges untrusted content, or consumes fast-import streams, upgrade promptly rather than relying on the recursive-clone workaround.

The practical takeaway

Git is a developer tool, but it is also a program that parses complex, attacker-controlled repository data. A clone command is not automatically equivalent to executing a build script, but this disclosure shows that some repository operations can reach code-execution paths before a developer has reviewed the project.

Update to a patched Git release wherever repositories are processed. Until then, avoid recursive clones of untrusted repositories and do not treat that temporary step as a complete fix. For teams, the most valuable follow-up is often not another policy document: it is finding the exact runner, container, IDE, or bundled client that performs checkout and proving that it now runs a patched version.

I write about developer tools, security, and AI engineering. Subscribe if you want more practical breakdowns like this.

How does your team handle submodules from forks or other untrusted repositories? Have you checked which Git binary your CI runner actually uses?

Sources

[1] Git security vulnerabilities announced

[2] Git v2.56.1 release notes

[3] Git clone documentation

[4] Git security advisory for CVE-2026-111760

Top comments (0)