Skip to content

git: Fix commit message generation in untrusted projects and block external diff#51323

Merged
Anthony-Eid merged 2 commits intomainfrom
50649-restricted-mode
Mar 13, 2026
Merged

git: Fix commit message generation in untrusted projects and block external diff#51323
Anthony-Eid merged 2 commits intomainfrom
50649-restricted-mode

Conversation

@dinocosta
Copy link
Copy Markdown
Member

@dinocosta dinocosta commented Mar 11, 2026

When on a untrusted project, if one was to try and use the commit generation functionality, the command would fail because of the -c diff.external configuration provided in GitBinary::build_command, as git would interpret this as "" and try to run that command.

This -c diff.external is a good safeguard to have on untrusted repositories because it prevents random commands, configured in .git/config from being run. For example, if one uses git config diff.external "touch bananas.txt" and then run git diff, a new bananas.txt file would be created.

However, it was still possible to bypass this safeguard using the following strategy:

  1. Specify a custom diff for a specific file format. For example, for markdown files, with printf '*.md diff=pwned\n' > .gitattributes
  2. Update the command run by the pwned diff, for example, git config diff.pwned.command "touch bananas.txt"
  3. Open Zed and attempt to generate a commit message in an untrusted repository and check that a new bananas.txt file was created

This is only prevented by using the --no-ext-diff flag on the diff command, so a new GitBinary::build_diff_command has been introduced which simply wraps GitBinary::build_command and adds the --no-ext-diff flag, if necessary.

As a side-effect, this also makes it so that generating a commit message in an untrusted repository works again, which was accidentally broken on #50649 .

Before you mark this PR as ready for review, make sure that you have:

  • Added a solid test coverage and/or screenshots from doing manual testing
  • Done a self-review taking into account security and performance aspects
  • Aligned any UI changes with the UI checklist

Closes #51249.

Release Notes:

  • Fixed commit message generation in untrusted repositories

When on a untrusted project, if one was to try and use the commit
generation functionality, the command would fail because of the `-c
diff.external` configuration provided in `GitBinary::build_command`, as
git would interpret this as `""` and try to run that command.

This `-c diff.external` is a good safeguard to have on untrusted
repositories because it prevents random commands, configured in
`.git/config` from being run. For example, if one uses `git config
diff.external "touch bananas.txt"` and then run `git diff`, a new
`bananas.txt` file would be created.

However, it was still possible to bypass this safeguard using the
following strategy:

1. Specify a custom diff for a specific file format. For example, for
   markdown files, with `printf '*.md diff=pwned\n' > .gitattributes`
2. Update the command run by the `pwned` diff, for example, `git config
   diff.pwned.command "touch bananas.txt"`
3. Open Zed and attempt to generate a commit message in an untrusted
   repository and check that a new `bananas.txt` file was created

This is only prevented by using the `--no-ext-diff` flag on the `diff`
command, so a new `GitBinary::build_diff_command` has been introduced
which simply wraps `GitBinary::build_command` and adds the
`--no-ext-diff` flag, if necessary.

As a side-effect, this also makes it so that generating a commit message
in an untrusted repository works again.
@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Mar 11, 2026
@zed-community-bot zed-community-bot bot added the staff Pull requests authored by a current member of Zed staff label Mar 11, 2026
@zed-codeowner-coordinator zed-codeowner-coordinator bot requested review from a team, kubkon and rtfeldman and removed request for a team March 11, 2026 20:07
@dinocosta dinocosta requested review from Anthony-Eid and removed request for kubkon and rtfeldman March 11, 2026 20:08
@dinocosta dinocosta assigned Anthony-Eid and dinocosta and unassigned kubkon Mar 11, 2026
@Anthony-Eid
Copy link
Copy Markdown
Contributor

Damn, nice research!

Is there any reason we couldn't unify GitBinary::build_diff_command and GitBinary::build_command?

Copy link
Copy Markdown
Contributor

@Anthony-Eid Anthony-Eid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me! I appreciate the descriptive PR message

@dinocosta
Copy link
Copy Markdown
Member Author

Damn, nice research!

Is there any reason we couldn't unify GitBinary::build_diff_command and GitBinary::build_command?

Sorry, I opened this late at night and was actually planning to leave a comment on this, we don't necessarily need GitBinary::build_diff_command, as we could always update just the RealGitRepository::diff implementation to also check GitBinary::is_trusted and pass --no-ext-diff in case it's false, seems like the only place where we actually run git diff from.

If we do wish to unify, I think we could probably update GitBinary::build_command to check if any of the args is the "diff" command and, if that's the case, add that --no-ext-diff argument. What do you think? Does this seem better? 🙂

Thank you for the review!

@Anthony-Eid
Copy link
Copy Markdown
Contributor

If --no-ext-diff is only valid with diff I wouldn't be against having a separate build. The reason I'm being pedantic about the GitBinary::build_command is I want to prevent any security issues in the future from users spawning a git command in a different way.

If you end up going with the separate build command functions we could put a debug assert in GitBinary::build_command that checks it's not used for diff commands, but I wonder if that would fail with our num stat diff?

I also think this is good to merge now, we can always improve forward and this seems important enough to get in and cherry pick to preview and maybe stable if it's affected there as well

* Remove `git::repository::GitBinary::build_diff_command`
* Update `git::repository::GitBinary::build_command` to check if `diff`
  is being used and, if that's the case and the repository is untrusted,
  add the `--no-ext-diff` flag
* Update the type signature of
  `git::repository::GitBinary::build_command` to avoid having to clone
  the `args` iterator, by accepting a `&[S]` instead of `impl
  IntoIterator<Item = S>`
@dinocosta
Copy link
Copy Markdown
Member Author

If --no-ext-diff is only valid with diff I wouldn't be against having a separate build. The reason I'm being pedantic about the GitBinary::build_command is I want to prevent any security issues in the future from users spawning a git command in a different way.

Makes total sense!

If you end up going with the separate build command functions we could put a debug assert in GitBinary::build_command that checks it's not used for diff commands, but I wonder if that would fail with our num stat diff?

I ended up pushing a commit – ae0906d – that does the check in build_command on whether the diff command is being used, to automatically add that --no-ext-diff flag if that's the case and we're working within an untrusted repository, let me know if this is better or if you'd rather I keep the build_diff_command with an assert and check whether that breaks the diff stats. Also updated the type signature to avoid having to clone the args just to check if diff is present but do let me know if you'd rather I revert this 🙇

I also think this is good to merge now, we can always improve forward and this seems important enough to get in and cherry pick to preview and maybe stable if it's affected there as well

I've confirmed this is only affecting Preview 🫡

@Anthony-Eid Anthony-Eid merged commit 697e5be into main Mar 13, 2026
28 checks passed
@Anthony-Eid Anthony-Eid deleted the 50649-restricted-mode branch March 13, 2026 14:08
@Anthony-Eid
Copy link
Copy Markdown
Contributor

/cherry-pick preview

github-actions bot pushed a commit that referenced this pull request Mar 13, 2026
…ternal diff (#51323)

When on a untrusted project, if one was to try and use the commit
generation functionality, the command would fail because of the `-c
diff.external` configuration provided in `GitBinary::build_command`, as
git would interpret this as `""` and try to run that command.

This `-c diff.external` is a good safeguard to have on untrusted
repositories because it prevents random commands, configured in
`.git/config` from being run. For example, if one uses `git config
diff.external "touch bananas.txt"` and then run `git diff`, a new
`bananas.txt` file would be created.

However, it was still possible to bypass this safeguard using the
following strategy:

1. Specify a custom diff for a specific file format. For example, for
markdown files, with `printf '*.md diff=pwned\n' > .gitattributes`
2. Update the command run by the `pwned` diff, for example, `git config
diff.pwned.command "touch bananas.txt"`
3. Open Zed and attempt to generate a commit message in an untrusted
repository and check that a new `bananas.txt` file was created

This is only prevented by using the `--no-ext-diff` flag on the `diff`
command, so a new `GitBinary::build_diff_command` has been introduced
which simply wraps `GitBinary::build_command` and adds the
`--no-ext-diff` flag, if necessary.

As a side-effect, this also makes it so that generating a commit message
in an untrusted repository works again, which was accidentally broken on
#50649 .

Before you mark this PR as ready for review, make sure that you have:
- [X] Added a solid test coverage and/or screenshots from doing manual
testing
- [X] Done a self-review taking into account security and performance
aspects
- [X] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- Fixed commit message generation in untrusted repositories
zed-zippy bot added a commit that referenced this pull request Mar 13, 2026
…ternal diff (#51323) (cherry-pick to preview) (#51492)

Cherry-pick of #51323 to preview

----
When on a untrusted project, if one was to try and use the commit
generation functionality, the command would fail because of the `-c
diff.external` configuration provided in `GitBinary::build_command`, as
git would interpret this as `""` and try to run that command.

This `-c diff.external` is a good safeguard to have on untrusted
repositories because it prevents random commands, configured in
`.git/config` from being run. For example, if one uses `git config
diff.external "touch bananas.txt"` and then run `git diff`, a new
`bananas.txt` file would be created.

However, it was still possible to bypass this safeguard using the
following strategy:

1. Specify a custom diff for a specific file format. For example, for
markdown files, with `printf '*.md diff=pwned\n' > .gitattributes`
2. Update the command run by the `pwned` diff, for example, `git config
diff.pwned.command "touch bananas.txt"`
3. Open Zed and attempt to generate a commit message in an untrusted
repository and check that a new `bananas.txt` file was created

This is only prevented by using the `--no-ext-diff` flag on the `diff`
command, so a new `GitBinary::build_diff_command` has been introduced
which simply wraps `GitBinary::build_command` and adds the
`--no-ext-diff` flag, if necessary.

As a side-effect, this also makes it so that generating a commit message
in an untrusted repository works again, which was accidentally broken on
#50649 .

Before you mark this PR as ready for review, make sure that you have:
- [X] Added a solid test coverage and/or screenshots from doing manual
testing
- [X] Done a self-review taking into account security and performance
aspects
- [X] Aligned any UI changes with the [UI

checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- Fixed commit message generation in untrusted repositories

Co-authored-by: Dino <dinojoaocosta@gmail.com>
tommyming pushed a commit to tommyming/zed that referenced this pull request Mar 15, 2026
…ternal diff (zed-industries#51323)

When on a untrusted project, if one was to try and use the commit
generation functionality, the command would fail because of the `-c
diff.external` configuration provided in `GitBinary::build_command`, as
git would interpret this as `""` and try to run that command.

This `-c diff.external` is a good safeguard to have on untrusted
repositories because it prevents random commands, configured in
`.git/config` from being run. For example, if one uses `git config
diff.external "touch bananas.txt"` and then run `git diff`, a new
`bananas.txt` file would be created.

However, it was still possible to bypass this safeguard using the
following strategy:

1. Specify a custom diff for a specific file format. For example, for
markdown files, with `printf '*.md diff=pwned\n' > .gitattributes`
2. Update the command run by the `pwned` diff, for example, `git config
diff.pwned.command "touch bananas.txt"`
3. Open Zed and attempt to generate a commit message in an untrusted
repository and check that a new `bananas.txt` file was created

This is only prevented by using the `--no-ext-diff` flag on the `diff`
command, so a new `GitBinary::build_diff_command` has been introduced
which simply wraps `GitBinary::build_command` and adds the
`--no-ext-diff` flag, if necessary.

As a side-effect, this also makes it so that generating a commit message
in an untrusted repository works again, which was accidentally broken on
zed-industries#50649 .

Before you mark this PR as ready for review, make sure that you have:
- [X] Added a solid test coverage and/or screenshots from doing manual
testing
- [X] Done a self-review taking into account security and performance
aspects
- [X] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- Fixed commit message generation in untrusted repositories
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement staff Pull requests authored by a current member of Zed staff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot generate AI commit message in a fresh git repository

3 participants