Block .git/modules/, warn on git-attribute/rebase paths, hint on submodule add#129
Merged
Block .git/modules/, warn on git-attribute/rebase paths, hint on submodule add#129
Conversation
…odule add DefaultDiffSecurityPatterns previously blocked only `.git/config` and `.git/hooks/` from flushing back to the host. `.git/modules/<name>/` carries the same RCE surface — `<name>/config` accepts exec-class keys, `<name>/hooks/` auto-fires on routine git operations — so add it to the hard-block list. Nothing else is added to the hard-block list: the deliberate design choice is that paths whose RCE surface only fires on explicit user action (`rebase --continue`, `git checkout` with a pre-defined filter driver, `git submodule update`) stay flushable and are surfaced via SensitivePathRules warnings instead. Blocking them would break legitimate agent workflows (resuming rebases, adding submodules, editing .gitattributes). Add four Tier 2 entries to DefaultSensitivePathRules (warn on stderr, still flush): - .gitattributes (basename) — can reference filter drivers (filter=/diff=/merge=) that execute during `git checkout`, `git archive`, or `git diff`. The filter definition itself must exist in the user's ~/.gitconfig for exploitation, so warn + flush lets routine edits (text/eol/binary attrs) proceed. - .gitmodules (basename) — submodule URLs are fetched on `git submodule update` (explicit user action). - .git/info/attributes (exact path) — same filter-driver surface as .gitattributes but scoped to the local worktree. - .git/rebase-merge/git-rebase-todo (exact path) — `exec <cmd>` directives run when the user runs `git rebase --continue`. To close the `git submodule add` UX rough edge — `.gitmodules` flushes but `.git/modules/<name>/` is silently hard-stripped, leaving the host with a half-populated submodule — emit a stderr note after successful flush pointing the user at `git submodule update --init` for recovery. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes a MEDIUM security finding — a compromised agent could write attacker-controlled content to submodule configs / hooks / git attributes / rebase-todo state and have it flushed back, giving RCE on the host via filter drivers, submodule hooks, or rebase
execdirectives.Design principle applied consistently: only hard-block paths whose RCE surface fires on routine git operations (hooks, config). Paths whose RCE requires an explicit user action (
rebase --continue,git submodule update,git checkoutwith a pre-configured filter driver) stay flushable and are surfaced via stderr warnings — blocking them would break legitimate agent workflows (resuming rebases, adding submodules, editing.gitattributes).Changes
DefaultDiffSecurityPatterns(hard-block, silent strip):.git/modules/— submodule configs/hooks have the same RCE surface as top-level.git/config/.git/hooks/, and they auto-fire on routine ops.DefaultSensitivePathRules— new Tier 2 entries (stderr WARNING, flush proceeds):.gitattributes(any depth) — can reference filter drivers (filter=/diff=/merge=) that execute ongit checkout,git archive,git diff. Filter definition must exist in the user's~/.gitconfigfor exploitation, so routine edits (text/eol/binary) still work..gitmodules(any depth) — submodule URLs fetched ongit submodule update..git/info/attributes— same filter-driver surface as.gitattributes, local-to-worktree..git/rebase-merge/git-rebase-todo—exec <cmd>directives run ongit rebase --continue.UX recovery hint: the one asymmetric side-effect —
.gitmodulesflushes but.git/modules/<name>/is silently hard-stripped, leaving the host with a half-populated submodule aftergit submodule add— is mitigated by a stderr note after successful flush pointing the user atgit submodule update --initto materialize the submodule gitdir.Workflows verified (via UX review)
.gitattributes/.gitmodules/.github/workflows//Makefile/Jenkinsfile— works with warninggit-rebase-todowarned)git am/git gc/ cherry-pick / edits.git/info/exclude— works silently.gitmodulesflushes, user gets recovery hint.git/hooks//.husky/— rejected (pre-existing policy, unchanged)Test plan
task fmt && task lint && task test— all greenpkg/domain/snapshot/{exclude,sensitive}_test.goandinternal/infra/exclude/loader_test.goassert both the new matches AND the negative cases (paths that MUST continue to sync back)bbox claude-code --no-mcp --exec /bin/sh -- -c 'ls /workspace/.git/info/'confirms.git/info/excludeis visible in the snapshot (not stripped) and VM cycles cleanly🤖 Generated with Claude Code