TL;DR — Security release: a repository's own .git/config could make git run a program of its choosing, and opening the folder was enough. Codeep now neutralises those settings on every git call it makes.
A follow-up to 3.4.0, from the same review applied to the macOS app: git reads settings from the repository it is run in, and several of them name a program git then runs. Codeep runs git by itself — the status line alone runs git status when a project opens — so a folder that arrived with its own .git (a zip, a tarball, a shared drive) could execute code before anything was typed. Reproduced, then closed, then attacked again over seven rounds of adversarial review with real git 2.54.
Security
- A repository's own git config could run a program of its choosing. Every
git call Codeep makes now neutralises the settings that name a command — core.fsmonitor, content filters (filter.<driver>.clean/smudge/process), diff.external and diff drivers, textconv, merge drivers, the gpg.* cluster, credential.helper, core.sshCommand, core.askPass, core.gitProxy, interactive.diffFilter, trailer commands, submodule.<name>.update, remote.<name>.uploadpack and receivepack, uploadpack.packObjectsHook, core.alternateRefsCommand, every alias the repository defines, and the pager, editor and signature-display settings. Settings in your own global config are left alone.
- It covers every path git is reached by: the status line,
/commit,
/diff, @git, the review, execute_command, a skill's command steps, and the terminal an editor runs commands in over ACP.
- The repository's submodules are read too — a submodule keeps its config
in .git/modules/<name>/config, which the superproject's own config listing never shows.
- A config Codeep cannot read completely (oversized, unparseable, timing
out) now refuses the git call instead of running it unprotected, and GIT_CONFIG_PARAMETERS is removed from the environment so it cannot re-enable anything.
execute_commandrefuses git arguments that aim git elsewhere:
--git-dir, --work-tree, --exec-path, --config-env, --attr-source, and -c for include.path, includeIf.*.path, attr.tree or any key that names a program. git -C is allowed and the repository it points at is the one that gets checked.
- Writing a file that decides what runs later now always asks, in every
confirmation mode, and fails when there is nobody to ask: anything under .git/, the hook directory the repository actually uses (including .githooks and .husky), .codeep/hooks/, .codeep/skills/, .codeep/agents/, .codeep/mcp_servers.json, .mcp.json and .codeep/config.json. The prompt says what the file controls. This covers the tools that take a path; it is not a boundary against a shell command you approved, which can write the same file with node, cp or tee.
- The editor terminal no longer receives your whole environment. Commands
sent over ACP carried every variable of the Codeep process, including API keys, and the ACP debug log mirrored them. Only the settings the hardening needs and the ordinary shell variables are sent now.
Upgrade notes
- **A repository that configures its own content filter stops Codeep's git
calls, unless the filter is one of the known integrations (git-lfs, git-crypt, nbstripout, git-annex, also when spelled with an absolute path). The message names the driver and the exact git config --unset. Turning off filter.<driver>.required is not** a fix: it makes git store the file's contents unfiltered. The same applies to a repo-set remote.<name>.uploadpack or receivepack, which no override can reach.
- **A leftover filter config refuses the repository even if nothing is routed
at it today.** Deciding that it is unused would mean re-implementing git's attribute lookup, which a security release is not the place for.
- Codeep's own read-only git calls run with hooks disabled. Hooks still run
for the commits and checkouts you trigger, as they do in your terminal.
- **
@git,/diffand the review no longer apply the repository's textconv or
external diff drivers**, so a repo that renders binaries for display shows the raw diff.
- Aliases the repository defines do not run through Codeep; the refusal
says so and names the alias.
- Checking a repository's config costs about 7 ms more per git call, and about
14 ms in a repository with submodules.
Fixed
/commitand the review saw the first changed file with two characters
missing from its name.
- Auto-commit said "No changes detected by git" when git had actually failed,
and did nothing at all in a repository with no commits yet.
- The status line went blank with no explanation when Codeep refused to run
git; it now says so once, with the setting and the command that clears it.
codeep hook installsaid "not a git repository" when git had been refused.
Internal
- 3850 tests. Every fix in this release was checked by putting the bug back and
watching the test fail.
- The test suite can no longer ask a human for anything: a fixture that ran
git credential fill reached the editor's askpass helper and waited for a password dialog, which stalled a release.