CSIPE

Published

- 17 min read

A Zipped Repository Can Run Before Your Coding Agent Asks


Books by the author

Compare all 5

As an Amazon Associate I earn from qualifying purchases. Buying through these links costs you nothing extra and helps pay for the blog.

A colleague sends you a zipped repository. You unpack it, change into the directory, and start a coding agent so it can explain the project. You have not approved a command. You have not even typed a prompt.

Yet the repository may already have had a chance to run one.

On 1 September 2026, Manifold Security published research into eight flaws across seven command-line coding agents. The researchers found that routine Git calls made by the tools could execute a command named in the received repository’s own local configuration. Four findings were still unpatched when Manifold retested current releases for publication (Manifold Security; The Hacker News).

The delivery condition matters. A normal git clone does not copy the source repository’s local .git/config, so the demonstrated path does not ride along with an ordinary clone. A zip file, shared folder, synchronised directory, or USB copy can preserve that hidden administrative directory. This is a narrow condition, but it lands squarely inside an ordinary development habit: accepting a project as files and opening it with a tool that tries to be helpful before asking what you want.

The lasting lesson is bigger than one Git setting or one agent release. Workspace trust cannot begin after software has already inspected the workspace by running authority-bearing helpers. Inspection must be passive, or it must happen inside a boundary that assumes the files are hostile.

What happened before the first prompt

A coding agent needs context. Before answering a question, it may check the current branch, find modified files, build a diff, or learn whether the working tree is clean. Git supplies all of that through familiar commands such as git status and git diff.

Those commands look harmless because developers run them constantly. They also do more than print text. Git may refresh its index, the internal record it uses to compare the working tree with committed content. During that refresh, Git can consult a filesystem-monitor helper selected by the core.fsmonitor setting.

A filesystem monitor exists to make large repositories faster. Instead of scanning every path, Git asks a helper which files changed. Git’s own documentation describes the monitor as a performance feature used by commands such as git status (Git documentation). The danger came from ordinary plumbing: intended Git behaviour combined with an agent call that retained repository-controlled settings.

Manifold calls the resulting class GitSpawn. In the reported paths, the agent launched a normal Git subprocess while gathering context. Git read the local repository configuration, found a helper command, and ran it with the developer’s operating-system privileges. The agent’s command-approval layer did not mediate that child process because, from the agent’s point of view, it had launched Git for its own housekeeping rather than a tool call requested by the model.

That sequence places execution before the visible decision point:

  1. A developer receives a directory that already includes its .git administrative data.
  2. The developer opens that directory with a coding agent or invokes a review command.
  3. The agent runs Git to collect project context.
  4. Git reads the repository-local setting and starts the configured helper.
  5. Only afterward does the user see a trust prompt, enter a request, or review a proposed command.

The result is local command execution as the account running the agent. Practical impact depends on that account. A disposable test user with an empty home directory offers little. A normal developer session may expose source trees, an SSH agent, cloud credentials, package-publishing tokens, browser sessions, build-signing access, or reachable internal services. The trigger is small; the surrounding authority decides the blast radius.

As of 2 September 2026, public reporting said there was no evidence that attackers had used these GitSpawn findings in the wild. This is a disclosure about a reproducible design flaw, not a report of a campaign. That evidence limit should keep the response proportionate. It should not excuse the architecture.

A clone and a copied repository are different objects

Developers often use “clone” to mean any folder containing a project. Git does not treat those objects as equivalent, and neither should an intake process.

An ordinary git clone transfers versioned objects and checks out a working tree. It creates fresh local administrative data at the destination. The source repository’s local .git/config sits outside the tracked project and stays behind. Manifold is therefore explicit that cloning a hostile URL, fetching from it, or pulling from it does not deliver the demonstrated core.fsmonitor configuration.

A copied directory is different. Zip the whole folder, including hidden files, and the local Git database can travel with it. The same is true of many shared-drive, synchronisation, backup, or removable-media workflows. When the receiver unpacks the directory, they inherit someone else’s repository objects and someone else’s local control settings.

That distinction is easy to miss because both directories pass the visual test. Each contains source files. Each may answer git status. Each can be opened in an editor. One was constructed locally from versioned content; the other may carry an unreviewed control plane in .git.

The practical rule is simple: if you trust the remote source, clone it yourself. Do not accept a full repository archive merely to save the sender a push. When an archive is unavoidable, treat .git as executable metadata and inspect or discard it before opening the project with an IDE, coding agent, build tool, or package manager.

Removing .git and creating a fresh repository can be appropriate when history is unnecessary, but it changes the object. Commit ancestry, branches, tags, submodule state, signatures, and local forensic clues may disappear. For a customer incident, legal handoff, or research sample, preserve the original archive separately and examine a copy in an isolated environment. Convenience and evidence preservation are different jobs.

A source archive created by a hosting platform usually contains tracked files without .git, which avoids this exact path. It can still contain dangerous build scripts, editor tasks, package hooks, or agent instructions. “No .git/config” means the GitSpawn route is absent. It does not mean opening or building the project is passive.

This is the useful boundary: versioned source is untrusted content; copied administrative state is untrusted control data. Both need review, but the second category can alter what supposedly read-only tools do while they inspect the first.

The sandbox was downstream of the dangerous action

Many coding agents offer command approvals, workspace-trust dialogs, or sandboxes. Those controls matter. They did not cover the paths described in this research because the vulnerable action happened in the agent’s own setup plumbing.

A model proposes a shell command, the product checks policy, and the user approves or denies it. That is the permission flow most people picture. GitSpawn took a side route. Product code decided that collecting repository context was safe, launched Git directly, and inherited Git’s own extension points. No model proposal existed for the policy layer to evaluate.

This is a common systems mistake: placing a strong gate around the obvious doorway while a maintenance corridor reaches the same room. The command was not “inside the sandbox and then escaped.” The process began outside the sandbox because the sandbox governed model-requested tools, not every subprocess the application itself could create.

The goose advisory makes the timing concrete. Before version 1.44.0, goose review ran git diff to collect the change it would review. A malicious local Git configuration could cause code to execute before goose contacted a model, without a submitted prompt, tool approval, or trust decision. The project fixed the issue in 1.44.0 and published CVE-2026-72718 (GitHub advisory).

OpenAI documented the same class for Codex under CVE-2026-19592. Affected Codex CLI versions automatically collected repository metadata without disabling the local monitor setting. The helper ran outside the command sandbox and without approval; Codex CLI 0.131.0 contained the fix, according to the published record (Debian Security Tracker).

Manifold reported that the main core.fsmonitor path in Claude Code was fixed by version 2.1.196 and that Cursor had also shipped a fix. It found goose fixed in 1.44.0. On 1 September, the researchers still reproduced separate or related paths in Qwen Code 0.22.3, Grok Build 1.0.13, Hermes Agent 0.21.0, and Claude Code’s ultrareview path on 2.1.252. The last Claude path used a different configuration key, which the researchers withheld while it remained unpatched.

Those details are dated for a reason. Product status can change quickly after publication. Check current vendor releases and advisories before acting on a version number copied from this article. The stable conclusion does not depend on the table staying current: a trust prompt cannot protect work that precedes it.

The fix also cannot be “show the prompt two hundred milliseconds earlier” if background code is free to interpret the workspace before the user’s answer. Software needs a pre-trust mode with a sharply smaller capability set. Better still, it should avoid running workspace-selected programs while deciding whether the workspace is trusted at all.

The repository had authority hidden in configuration

Calling .git/config metadata makes it sound inert. Some entries are descriptive. Others select programs. That difference matters more than the file extension or directory name.

Git has accumulated extension points because development workflows need them. Filters can transform content. Diff and merge drivers can invoke specialised programs. Hooks automate repository events. Filesystem monitors accelerate change detection. These are useful features in a repository you administer. In a directory someone else assembled, they are possible execution routes.

The exact GitSpawn demonstration centred mostly on core.fsmonitor, and the public sources intentionally avoid turning every remaining route into a recipe. Defensive teams do not need a complete catalogue to adopt the right model. Any repository-controlled value that can name a command, load code, redirect a helper, or influence a subprocess deserves the same review as a script.

This reframes a familiar question. “Did the agent run a command?” is too narrow. The better question is: “Did any component interpret untrusted project state in a way that could cause an effect?” The component may be Git, a language runtime, an editor extension host, a package manager, a notebook server, a container builder, or a test framework.

The Marimo notebook flaw disclosed in August 2026 made the same timing error through a different mechanism. A notebook could carry a local tool-server command that started when the file was opened for editing, before a cell ran. GitSpawn shows the repository version of that pattern. A file or folder that looks like input also contains instructions for constructing the environment around that input.

Teams get into trouble when they classify settings by where they are stored instead of what they can cause. A colour theme and a process path may both be called configuration. One changes presentation. The other grants execution authority. An API base URL may look like a string, but it decides where credentials travel. A mounted socket may look like a path, but it can convey host control.

A useful review vocabulary names effects rather than formats:

  • Presentation settings alter appearance without touching identities, processes, or network destinations.
  • Reproducibility settings select versions and dependencies, which may cause downloads or installation code to run.
  • Authority settings create processes, expose credentials, mount host resources, or choose network endpoints.
  • Persistence settings change what happens during later opens, builds, commits, logins, or updates.

That classification gives reviewers something concrete to ask. Portable project files may reasonably carry presentation and some reproducibility preferences. Authority and persistence should cross a separate trust decision, come from team-managed policy, or run inside a disposable environment that contains nothing valuable.

Updating the agent closes a path, not the intake gap

If a fixed release exists for your tool, install it. That is the fastest way to close the known implementation path. Then verify the running version in every place the tool exists, including workstation package managers, editor integrations, development containers, remote workspaces, and CI images.

Do not stop at changing a manifest. A pinned global package may remain on a laptop. A base image may still contain last month’s binary. A desktop application and its command-line companion may update separately. The version that starts inside the received repository is the one that matters.

For products listed as unpatched on 1 September, consult the vendor’s current release notes before using them in a copied repository. If no confirmed fix now exists, do not rely on careful prompting. The vulnerable work can happen before a prompt. Restrict the workflow instead: clone trusted remotes, inspect archives outside the agent, and open unknown projects only in a stripped, disposable account or virtual machine.

Manifold suggests that vendors neutralise repository-controlled configuration on their own background Git calls, for example by overriding core.fsmonitor when asking for status. That closes the documented sink. A mature fix also inventories every pre-trust subprocess and asks which local, global, environment, executable-path, and workspace inputs can alter it.

A narrow override can age badly when the product adds another Git operation or Git gains another extension point. Vendors should centralise repository inspection behind one hardened wrapper, pass an explicit safe configuration, control the executable being launched, use a predictable environment, and test hostile repositories as part of release gates. The test should fail if any marker process starts before trust is granted.

The wrapper also needs to preserve useful behaviour after trust. Developers may intentionally use a filesystem monitor in a very large monorepo. A product can disable such helpers during pre-trust inspection, then permit an approved configuration later inside the normal execution policy. Security does not require deleting useful Git features. It requires stopping an unknown directory from enabling them silently.

Teams should ask one more question after an update: did anyone open a copied repository with an affected version? The answer decides whether this is only patch management or a small incident review. Search file transfers, download folders, support attachments, consultant handoffs, shared drives, and extracted archives. Focus on directories that retained .git and were opened with a listed tool during its affected window.

An affected version plus a copied repository is still not proof of execution. Inspect the local Git configuration and available endpoint evidence. If an authority-bearing setting is present, scope what the user account could reach at that time. Rotate relevant credentials and rebuild the workstation only when evidence and reachable authority justify those steps. Precision prevents both complacency and needless panic.

A safer way to receive and inspect a project

The intake path should make the safe action easier than opening an archive in the everyday developer session. A short procedure is enough if each step protects a real boundary.

  1. Record where the project came from. Keep the sender, remote URL, delivery method, and expected revision. “From a colleague” is not provenance if the colleague downloaded it elsewhere. A commit identifier or signed release gives you something to compare.

  2. Prefer a fresh clone from the expected remote. Clone with your standard Git client into a new directory. Check the remote and revision before starting an agent. This prevents the sender’s local .git/config from becoming yours, though tracked project files remain untrusted.

  3. Quarantine full-directory archives. If you must accept one, do not browse into it with an IDE or agent. List hidden entries using a passive archive viewer, then extract it in a disposable environment without personal credentials, SSH agent forwarding, production mounts, or broad internal access.

  4. Inspect administrative and startup surfaces. Review .git/config and other Git administration data. Then inspect tracked files that can start work automatically, including editor tasks, development-container setup, package scripts, build files, test configuration, notebook metadata, and agent instructions. The goal is to find effects, not merely suspicious words.

  5. Reconstruct a clean working copy. When history matters, create a fresh clone from a verified remote and compare the supplied revision there. When only source matters, copy reviewed tracked content into a new directory and initialise fresh administrative state. Preserve the original separately if it may be evidence.

  6. Make the first active open disposable. Run the editor, agent, build, or tests in a short-lived workspace with no personal secrets and a deny-by-default network policy. Grant package registries or documentation endpoints deliberately. Delete the workspace after the review.

  7. Promote by evidence. Move the project into the normal development environment only after its origin, revision, authority-bearing settings, and required startup actions are understood. Record any exceptions so the next developer does not repeat the investigation.

This sequence is not reserved for malware samples. It fits take-home exercises, customer reproductions, inherited contractor work, incident bundles, acquisition reviews, and old projects recovered from backup. Most will be benign. The boundary exists because benign intent does not make copied control data safe by construction.

A small team can implement the same idea without a dedicated security platform. Give developers a clean virtual machine template, a script that reports hidden control surfaces without executing project tools, and a documented route for cloning from approved remotes. Remove production credentials from the first-open environment. Make escalation easy when the project genuinely needs special access.

Large organisations can enforce more of it. Email and chat gateways can flag archives containing .git. Endpoint rules can record coding-agent child processes before trust. Managed development environments can separate intake from production-capable workspaces. Policy can block personal SSH agents and cloud credentials from disposable review sessions. Another warning dialog would add little; less ambient authority at the moment of greatest uncertainty would add much more.

What agent builders should test before the next release

GitSpawn is useful to product teams because it exposes a testable design boundary. “We have a sandbox” is a feature claim. “No untrusted workspace state can start a host process before trust” is a security property.

Begin at process startup and trace every action before the first user-approved effect. Which commands run? Which configuration layers do they read? How is the executable resolved? Which environment variables survive? Can the workspace select a helper, plugin, filter, hook, formatter, language server, package source, or network destination? Product code that considers a command read-only may invoke a tool with its own execution model.

Then test a hostile workspace without publishing a weaponised sample. A fixture can point every authority-bearing setting at a harmless marker program that writes only inside a temporary test directory. Start the agent in each supported mode. The test passes only when no marker appears before trust and no process escapes the intended isolation afterward.

Exercise entry points separately. Startup, review, resume, sub-agent creation, worktree creation, indexing, search, and editor integration may use different code paths. Manifold found two distinct Claude Code paths, which is exactly why fixing one call does not prove the property across the product.

Treat the toolchain as part of the product. If the agent launches system Git, then Git configuration, executable lookup, environment handling, and child-process authority are inside the threat model. The same applies to shells, compilers, package managers, browsers, document converters, and language servers. Outsourcing work to a mature binary does not outsource the trust decision.

Finally, log enough to investigate a failure. Record which pre-trust subprocesses ran, the fixed arguments supplied by the product, the configuration sources permitted, and whether the user had granted workspace trust. Avoid capturing source code or secrets by default. A team should be able to answer whether a helper started without turning every developer machine into a surveillance system.

The Secure Harness argues that agent safety comes from boundaries around effects, not confidence in the model’s intentions. GitSpawn sharpens that point: the model was not involved. The harness must include the ordinary software wrapped around it, especially the code that runs before anyone thinks the agent has begun working.

The first read has to be genuinely passive

A zipped repository is not the same thing as source fetched into a fresh clone. It may carry local administrative state that changes how familiar tools behave. On 1 September 2026, that difference was enough to put routine context gathering ahead of the trust prompt in several popular coding agents.

Updating fixed versions is necessary. The durable correction is to redesign first contact with a project. Unknown files should be inspected without inheriting their execution choices. When active tooling is necessary, it should run in a place where a surprise process has little to reach and nowhere useful to send what it finds.

The plain lesson fits on one line: a workspace is untrusted before the agent reads it, not after the agent asks.

If you want practical security and AI engineering explained without the daily noise, subscribe to the newsletter. It is one email per month.

Sources