Commits and pushes: not the interesting part

An agent running git add, git commit, or git push is doing exactly what those commands always do — there's no special trust tier inside Git for who's typing. The access it needs to push — a credential helper, a loaded SSH key — is the same access already covered for the account in general. That's real, but it's not specific to Git; it's the same filesystem-access story with a Git-shaped example.

Where it actually gets interesting: hooks

Git has a real, deliberate safety property most people don't know about: hooks live in .git/hooks/, which is not part of the tracked working tree — a plain git clone doesn't install a malicious hook script from the repository you just cloned, by design. That property is exactly what gets bypassed when a project uses a hook-management tool (Husky, the pre-commit framework, Lefthook) that version-controls hook scripts and symlinks or copies them into .git/hooks/ as part of setup. Once that's happened, a hook committed to the repository — potentially by a PR, potentially by an agent — can execute automatically on the next commit or checkout, which is the exact safety property Git built in specifically not existing anymore for that project.

There's a documented CVE-class version of this too: a symlink pointing a checkout path at a submodule's hooks directory can cause a submodule's post-checkout hook to run unintentionally after checkout, patched in current Git but a real historical vulnerability class, not a theoretical one.

The chain that actually matters: install scripts feed hooks

Dependency installation already runs arbitrary code by design — that's not new here. What's specific to Git is how directly that connects to the hooks problem above: an npm install in a project using Husky commonly runs a postinstall script that installs Git hooks as a normal, intended part of setup. An agent that clones a repository and runs its stated setup steps — exactly what it was asked to do — can end up with hooks installed that execute on every subsequent commit, without ever having been told "install a Git hook."

What ends up committed isn't always what you'd have committed

A human developer has an instinct for what shouldn't go in a commit — a stray .env file, a debug print with a token in it, a half-finished credential test. An agent doesn't have that instinct unless something explicitly gives it one; it stages and commits whatever the task seemed to call for. The realistic scenario covered separately — an agent reading a .env file while debugging — becomes a genuinely different problem the moment that file's contents end up copied into a generated fix, a test fixture, or a commit message.

The actual mitigation

None of this is solved by asking the agent to be more careful — it's the same conclusion as everywhere else on this blog: the boundary has to sit outside the agent's own process. A disposable workspace that's discarded after the task, covered in what is a disposable development environment, means a hook that got installed, or a credential that got read, doesn't outlive the session that caused it. Combined with the isolation levels in the security deep dive, that's the actual answer — not a more disciplined agent, an environment where its mistakes don't compound.

Related reading: how AI coding agents use your computer, what an agent can actually access, running AI agents safely in an isolated VM, and the full checklist this post's mitigation is one item on. Or download Velo Workspaces and try it yourself.