* [RCF] Secure git against involuntary arb. code execution without feature loss
@ 2025-10-08 21:02 Michael Lohmann
2025-10-08 21:30 ` Taylor Blau
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Michael Lohmann @ 2025-10-08 21:02 UTC (permalink / raw)
To: git
Hello everyone,
Hooks, as well as certain config (e.g. `core.pager`) can do automatic
code execution for you. In general, this is a great feature and should
be kept without the user noticing any changes.
BUT if you download a random folder which to you unknowingly is a repo
and either you or e.g. your command line prompt automatically executes a
simple `git status`, it feels bad if this results in arbitrary code
execution (ACE), e.g.:
https://www.sonarsource.com/blog/securing-developer-tools-git-integrations/
and
https://github.com/justinsteven/advisories/blob/main/2022_git_buried_bare_repos_and_fsmonitor_various_abuses.md
Apart from one core maintainer, all git user I talked to were surprised
and shocked by how simple an exploit like this was.
* Proposed solution (keeping all existing features):
- On first use, git generates a secret "token" (e.g. a random string in
~/.gitsecret)
- On calling `git init` or `git clone`, the secret is copied into the
new .git directory and serves as proof that this clone was created by
this user
- Before executing any user-defined code, check for the local token:
- If present, proceed as usual.
- Otherwise abort.
* Benefit:
- Protects users from ACE when interacting with untrusted repositories.
- Editors would no longer need to prompt the user for "Do you trust this
repository?" in most cases, because git could prove the clone is user
generated.
- For new clones, the user wouldn't even notice a change.
* Drawbacks:
- Existing clones would need manual approval once (e.g., via a new
`git allow` command).
* Migration strategy to ease adoption (risks to be weight up):
- A future minor release of `git` could already silently add the
token to all clones it is executed in.
- Even if the repo was malicious, ACE has already occured,
- Since the ACE would have already occured, chances are, other forms of
persistence had been taken
- By the time git 3.0 introduced the breaking change, most active clones
would be migrated, so users would only manually need to act, if they
have very infrequently used clones.
* Prototype:
On my machine `git` resolves to a 150 line bash wrapper script with a
rough implementation this proposal:
https://git.lohmann.sh/michael/nixos-config/src/branch/main/modules/git.sh
With that, `git` is no longer vulnerable against these kinds of attacks.
I also added some more background information/POC in a blog post:
https://www.lohmann.sh/en/nuggits/002-dangerous-git/
Yes, I know even despite the "silent migration" this would be probably
lead to some pain for some people on the initial adoption of git v3, but
it would make it much safer for everyone to use and in the long run,
nobody would notice. What are your thoughts of weighing long-term risks
with the short-term pain of adopting something like this? Any other
ideas on how to solve this even better?
Feedback welcome!
Michael Lohmann
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-08 21:02 [RCF] Secure git against involuntary arb. code execution without feature loss Michael Lohmann
@ 2025-10-08 21:30 ` Taylor Blau
2025-10-08 21:34 ` rsbecker
2025-10-08 21:49 ` Taylor Blau
2025-10-08 21:35 ` brian m. carlson
2025-10-09 5:24 ` Jeff King
2 siblings, 2 replies; 10+ messages in thread
From: Taylor Blau @ 2025-10-08 21:30 UTC (permalink / raw)
To: Michael Lohmann; +Cc: git
On Wed, Oct 08, 2025 at 11:02:03PM +0200, Michael Lohmann wrote:
> * Proposed solution (keeping all existing features):
> - On first use, git generates a secret "token" (e.g. a random string in
> ~/.gitsecret)
> - On calling `git init` or `git clone`, the secret is copied into the
> new .git directory and serves as proof that this clone was created by
> this user
Sure, but the problem is not with direct clones (at least, not using the
--local optimization), but with clones that recursively clone other
submodules.
If I clone a repository with --recurse-submodules, I imagine that this
proposal would *not* suggest copying this token into the recursively
cloned submodules, right?
proposal improves the experience
> - Editors would no longer need to prompt the user for "Do you trust this
> repository?" in most cases, because git could prove the clone is user
> generated.
If the above is true (that Git would not copy the token into recursively
cloned submodules), then I admit to struggling a bit to see how this
proposal would remove the need to consult the user in this case. Instead
of the editor doing it, the user would need to do it themselves?
Thanks,
Taylor
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-08 21:30 ` Taylor Blau
@ 2025-10-08 21:34 ` rsbecker
2025-10-08 21:49 ` Taylor Blau
1 sibling, 0 replies; 10+ messages in thread
From: rsbecker @ 2025-10-08 21:34 UTC (permalink / raw)
To: 'Taylor Blau', 'Michael Lohmann'; +Cc: git
On October 8, 2025 5:30 PM, Taylor Blau wrote:
>On Wed, Oct 08, 2025 at 11:02:03PM +0200, Michael Lohmann wrote:
>> * Proposed solution (keeping all existing features):
>> - On first use, git generates a secret "token" (e.g. a random string in
>> ~/.gitsecret)
>> - On calling `git init` or `git clone`, the secret is copied into the
>> new .git directory and serves as proof that this clone was created by
>> this user
>
>Sure, but the problem is not with direct clones (at least, not using the --local
>optimization), but with clones that recursively clone other submodules.
>
>If I clone a repository with --recurse-submodules, I imagine that this proposal
>would *not* suggest copying this token into the recursively cloned submodules,
>right?
>proposal improves the experience
>
>> - Editors would no longer need to prompt the user for "Do you trust this
>> repository?" in most cases, because git could prove the clone is user
>> generated.
>
>If the above is true (that Git would not copy the token into recursively cloned
>submodules), then I admit to struggling a bit to see how this proposal would
>remove the need to consult the user in this case. Instead of the editor doing it, the
>user would need to do it themselves?
I am wondering why this approach cannot be made more general. If there is
a tokenization framework built into git that organizations can use for integration,
they should be able to plug-in their own approved tokenization solutions, which
have already been vetted by the security groups. I am concerned that we are
potentially opening up git to CVEs due to insufficiently secure tokens that are
outside our specific domain.
--Randall
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-08 21:02 [RCF] Secure git against involuntary arb. code execution without feature loss Michael Lohmann
2025-10-08 21:30 ` Taylor Blau
@ 2025-10-08 21:35 ` brian m. carlson
2025-10-08 22:25 ` Michael Lohmann
2025-10-09 5:24 ` Jeff King
2 siblings, 1 reply; 10+ messages in thread
From: brian m. carlson @ 2025-10-08 21:35 UTC (permalink / raw)
To: Michael Lohmann; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 2951 bytes --]
On 2025-10-08 at 21:02:03, Michael Lohmann wrote:
> Hello everyone,
Hi,
> Hooks, as well as certain config (e.g. `core.pager`) can do automatic
> code execution for you. In general, this is a great feature and should
> be kept without the user noticing any changes.
>
> BUT if you download a random folder which to you unknowingly is a repo
> and either you or e.g. your command line prompt automatically executes a
> simple `git status`, it feels bad if this results in arbitrary code
> execution (ACE), e.g.:
>
> https://www.sonarsource.com/blog/securing-developer-tools-git-integrations/
>
> and
>
> https://github.com/justinsteven/advisories/blob/main/2022_git_buried_bare_repos_and_fsmonitor_various_abuses.md
>
> Apart from one core maintainer, all git user I talked to were surprised
> and shocked by how simple an exploit like this was.
>
> * Proposed solution (keeping all existing features):
> - On first use, git generates a secret "token" (e.g. a random string in
> ~/.gitsecret)
> - On calling `git init` or `git clone`, the secret is copied into the
> new .git directory and serves as proof that this clone was created by
> this user
> - Before executing any user-defined code, check for the local token:
> - If present, proceed as usual.
> - Otherwise abort.
This has all of the downsides of our existing per-Unix user approach and
is also more complicated. You'll notice that when we changed to the
per-Unix user approach, that broke containers, shared repositories, and
even the detection of whether a directory _is_ a repository, and this
would do the same thing. It would be even worse for containers because
if you copied a token into the container from the container user, you'd
end up polluting that directory with lots of useless tokens that never
get cleaned up.
It is also easy to bypass, since if we share multiple repositories as
collaborators, as soon as I can read the secret from one of them, I can
then write it into any other location. It would even be sufficient if
we were users on the same system (such as is common in universities or
some businesses) and I could read the repository. Many websites even
accidentally expose their `.git` directories, which would not only
expose their repository but also allow attacks against all of the
administrator's repositories.
What would be better to see instead is a config option that restricts
which external commands (via config options or hooks) can be executed
from local config. Then it would be possible to say, "Never honour
local config to execute code." With `includeIf`, this can allowlist
certain repositories to do that and leave the rest disabled.
Maybe something like this:
[safe]
config = core.editor
config = core.fsmonitor
hook = pre-receive
If you wanted to implement _that_, I'd be all over it.
--
brian m. carlson (they/them)
Toronto, Ontario, CA
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-08 21:30 ` Taylor Blau
2025-10-08 21:34 ` rsbecker
@ 2025-10-08 21:49 ` Taylor Blau
2025-10-08 22:09 ` Michael Lohmann
1 sibling, 1 reply; 10+ messages in thread
From: Taylor Blau @ 2025-10-08 21:49 UTC (permalink / raw)
To: Michael Lohmann; +Cc: git
On Wed, Oct 08, 2025 at 05:30:08PM -0400, Taylor Blau wrote:
> On Wed, Oct 08, 2025 at 11:02:03PM +0200, Michael Lohmann wrote:
> > * Proposed solution (keeping all existing features):
> > - On first use, git generates a secret "token" (e.g. a random string in
> > ~/.gitsecret)
> > - On calling `git init` or `git clone`, the secret is copied into the
> > new .git directory and serves as proof that this clone was created by
> > this user
>
> Sure, but the problem is not with direct clones (at least, not using the
> --local optimization), but with clones that recursively clone other
> submodules.
This is a think-o. I meant to ask whether or not we would respect the
token from the top-most $GIT_DIR in nested bare repositories. I imagine
we would not (otherwise this proposal would not provide any additional
security guarantees), and so...
> > - Editors would no longer need to prompt the user for "Do you trust this
> > repository?" in most cases, because git could prove the clone is user
> > generated.
>
> If the above is true (that Git would not copy the token into recursively
> cloned submodules), then I admit to struggling a bit to see how this
> proposal would remove the need to consult the user in this case. Instead
> of the editor doing it, the user would need to do it themselves?
The rest is the same as before (swapping submodules for nested bare
repositories).
Thanks,
Taylor
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-08 21:49 ` Taylor Blau
@ 2025-10-08 22:09 ` Michael Lohmann
0 siblings, 0 replies; 10+ messages in thread
From: Michael Lohmann @ 2025-10-08 22:09 UTC (permalink / raw)
To: Taylor Blau; +Cc: git
> On 8. Oct 2025, at 23:49, Taylor Blau <me@ttaylorr.com> wrote:
>
> On Wed, Oct 08, 2025 at 05:30:08PM -0400, Taylor Blau wrote:
>> On Wed, Oct 08, 2025 at 11:02:03PM +0200, Michael Lohmann wrote:
>>> * Proposed solution (keeping all existing features):
>>> - On first use, git generates a secret "token" (e.g. a random string in
>>> ~/.gitsecret)
>>> - On calling `git init` or `git clone`, the secret is copied into the
>>> new .git directory and serves as proof that this clone was created by
>>> this user
>>
>> Sure, but the problem is not with direct clones (at least, not using the
>> --local optimization), but with clones that recursively clone other
>> submodules.
>
> This is a think-o. I meant to ask whether or not we would respect the
> token from the top-most $GIT_DIR in nested bare repositories. I imagine
> we would not (otherwise this proposal would not provide any additional
> security guarantees), and so...
My understanding was that submodules would add their own git folder in
the top-level .git/modules/my-submodule, so obviously in order to trust
a submodule, you need to "sign" these too and you could automatically
also with --recursive.
(Sorry @Taylor - I missed adding the whole list as recipient, so you get
this twice...)
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Re: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-08 21:35 ` brian m. carlson
@ 2025-10-08 22:25 ` Michael Lohmann
0 siblings, 0 replies; 10+ messages in thread
From: Michael Lohmann @ 2025-10-08 22:25 UTC (permalink / raw)
To: sandals; +Cc: git, git
(Sorry @Brian, the first time I forgot to add the mailing list in cc,
and the second time I didn't have my mail client under control adding
HTML... Now trying with send-mail again in order to try and reduce the
possible errors. I am sorry, I am still quite inexperienced with the
mailing list and you need to suffer from my stupid mistakes!)
On Wed, 8 Oct 2025 21:35:56, brian m. carlson wrote:
> This has all of the downsides of our existing per-Unix user approach and
> is also more complicated. You'll notice that when we changed to the
> per-Unix user approach, that broke containers, shared repositories, and
> even the detection of whether a directory _is_ a repository, and this
> would do the same thing. It would be even worse for containers because
> if you copied a token into the container from the container user, you'd
> end up polluting that directory with lots of useless tokens that never
> get cleaned up.
Since I never worked in such a scenario, I think I am missing the full
implications. Instead of always requiring that, you could simply set
something like GIT_ALLOW=true or pass `--allow` (or maybe even a _global
only_ config `safe.allow = *` and then you explicitly opt out of this
protection for cases like this.
> It is also easy to bypass, since if we share multiple repositories as
> collaborators, as soon as I can read the secret from one of them, I can
> then write it into any other location.
Then instead of having a single file with all the tokens of users,
create different files with the respective user as the only one allowed
to read.
> It would even be sufficient if we were users on the same system (such
> as is common in universities or some businesses) and I could read the
> repository. Many websites even accidentally expose their `.git`
> directories, which would not only expose their repository but also
> allow attacks against all of the administrator's repositories.
What is different to the current situation then, apart from that you
specifically have to leak that secret and you now have to be targeted
individually and if you notice it being compromised you can rotate it?
Maybe instead of a shared global secret, create individuals you can
revoke independently?
> What would be better to see instead is a config option that restricts
> which external commands (via config options or hooks) can be executed
> from local config. Then it would be possible to say, "Never honour
> local config to execute code." With `includeIf`, this can allowlist
> certain repositories to do that and leave the rest disabled.
>
> Maybe something like this:
>
> [safe]
> config = core.editor
> config = core.fsmonitor
> hook = pre-receive
Interesting idea!
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-08 21:02 [RCF] Secure git against involuntary arb. code execution without feature loss Michael Lohmann
2025-10-08 21:30 ` Taylor Blau
2025-10-08 21:35 ` brian m. carlson
@ 2025-10-09 5:24 ` Jeff King
2025-10-09 22:43 ` Michael Lohmann
2025-10-13 9:57 ` Submitted patches for "assume unsafe" Michael Lohmann
2 siblings, 2 replies; 10+ messages in thread
From: Jeff King @ 2025-10-09 5:24 UTC (permalink / raw)
To: Michael Lohmann; +Cc: git
On Wed, Oct 08, 2025 at 11:02:03PM +0200, Michael Lohmann wrote:
> Hooks, as well as certain config (e.g. `core.pager`) can do automatic
> code execution for you. In general, this is a great feature and should
> be kept without the user noticing any changes.
>
> BUT if you download a random folder which to you unknowingly is a repo
> and either you or e.g. your command line prompt automatically executes a
> simple `git status`, it feels bad if this results in arbitrary code
> execution (ACE), e.g.:
We've discussed this a few times over the years. The most recent one I
can remember is:
https://lore.kernel.org/git/ZZr-JLxubCvWe0EU@tapette.crustytoothpaste.net/
I think there are two somewhat orthogonal issues to consider:
1. How does Git behave differently in an "unsafe" context? In the
thread above, I propose that it should skip loading config from the
repo-level $GIT_DIR/config file, and turn off hooks inside the
repo. Elsewhere, others have proposed finer-grained control (like
specific config options). IMHO the most important thing here is
maintainability, and having a scheme where we do not accidentally
add code that lets an untrusted repository do bad things.
2. How does the user tell Git which repos are safe or unsafe? You've
got a scheme here for marking user-created repositories with a
secret token. I think that could work, but there are other simpler
methods. E.g., we could pass down information through the
environment (like we do already for security features like
GIT_ALLOW_PROTOCOL), or mark a list of safe directories in user- or
system-level config (like we have already with safe.directories).
It's perhaps even reasonable to have multiple such mechanisms, as
they have different tradeoffs in convenience and security.
So in some sense I think talking about this token scheme and Git 3.0
compatibility is putting the cart before the horse. We need (1) first.
And then once we have it, I think the simplest thing is not turning it
on all the time, but letting commands opt into it through command-line
options and environment variables. So you could imagine git-prompt
running "git --assume-unsafe" or setting "GIT_ASSUME_UNSAFE=1" in the
environment. People who want to be more paranoid can set that variable
for their normal commands to opt into greater security (at the cost of
convenience).
Then once we have some practical experience with the system, we can
consider whether we should flip the default. And in the meantime we can
experiment with idea like your token scheme.
-Peff
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RCF] Secure git against involuntary arb. code execution without feature loss
2025-10-09 5:24 ` Jeff King
@ 2025-10-09 22:43 ` Michael Lohmann
2025-10-13 9:57 ` Submitted patches for "assume unsafe" Michael Lohmann
1 sibling, 0 replies; 10+ messages in thread
From: Michael Lohmann @ 2025-10-09 22:43 UTC (permalink / raw)
To: peff; +Cc: git, git
TL;DR: Thanks to all peoples input I just mentally untangeled/refactored
a few things about the discusion for myself:
* Current situation:
git assumes an unsafe repo, if neither
a) the user owns it, nor
b) it is included in "safe.directory" config
and then refuses any operation.
* Suggestions from the discussion:
1) The suggested "token" approach is just an additional way to set the
current state of allow "safe.directory" for repos _created_ by this
user
2) The suggested --assume-(un)safe / GIT_ASSUME_(UN)SAFE are additional
ways of setting the same state temporarily
3) There are suggested improvements on not blankly refusing operation at
all if assumed to be unsafe
4) The _enforcement_ part of the RFC is about dropping the check for the
owner of the repo to assume if safe or not
I think 1)-3) are relatively independent of one another to discuss,
whereas 4) probably requires all others to be viable.
And now for the long answer:
> We've discussed this a few times over the years. The most recent one I
> can remember is:
>
> https://lore.kernel.org/git/ZZr-JLxubCvWe0EU@tapette.crustytoothpaste.net/
>
> 1. How does Git behave differently in an "unsafe" context?
> In the thread above, I propose that it should skip loading config
> from the repo-level $GIT_DIR/config file, and turn off hooks
> inside the repo.
Indeed it would be a lot nicer, if git still worked and only showed a
(maybe hideable) warning. As mentioned in the above conversation, the
config parser could only extract the minimum required fields in the
assumed unsafe state and the hooks would be disabled, too.
> 2. How does the user tell Git which repos are safe or unsafe? You've
> got a scheme here for marking user-created repositories with a
> secret token. I think that could work, but there are other simpler
> methods. E.g., we could pass down information through the
> environment
I am not sure I can follow you. Just as an overwrite like you mentioned
below / as in suggestion 2)?
> or mark a list of safe directories in user- or system-level
> config (like we have already with safe.directories).
> It's perhaps even reasonable to have multiple such mechanisms, as
> they have different tradeoffs in convenience and security.
Indeed! E.g. for "automated trusting" on init/clone the path based
approach is probably not the best, since
a) if the user runs `git init /trusted && mv /trusted /elsewhere`, all
of the sudden git would no longer work in that repo and
b) now the path "/trusted" is vulnerable, unknown to the user.
> So in some sense I think talking about this token scheme and Git 3.0
> compatibility is putting the cart before the horse. We need (1) first.
IMHO, an option on how to _detect_ if this repo is a "safe.directory"
would not depend on improvements on how to _act_ upon it (or the other
way around). Yes - to _enforce_ not whitelisting all user owned repos by
default any more, both are probably needed. So indeed this part is more
speculative.
-Michael
^ permalink raw reply [flat|nested] 10+ messages in thread
* Submitted patches for "assume unsafe"
2025-10-09 5:24 ` Jeff King
2025-10-09 22:43 ` Michael Lohmann
@ 2025-10-13 9:57 ` Michael Lohmann
1 sibling, 0 replies; 10+ messages in thread
From: Michael Lohmann @ 2025-10-13 9:57 UTC (permalink / raw)
To: peff; +Cc: git, git
Hello!
As a first step, here are the patches for "--assume-unsafe" /
"GIT_ASSUME_UNSAFE" / "safe.assumeUnsafe":
https://lore.kernel.org/git/20251013094152.23597-1-git@lohmann.sh/
-Michael
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-10-13 9:57 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-08 21:02 [RCF] Secure git against involuntary arb. code execution without feature loss Michael Lohmann
2025-10-08 21:30 ` Taylor Blau
2025-10-08 21:34 ` rsbecker
2025-10-08 21:49 ` Taylor Blau
2025-10-08 22:09 ` Michael Lohmann
2025-10-08 21:35 ` brian m. carlson
2025-10-08 22:25 ` Michael Lohmann
2025-10-09 5:24 ` Jeff King
2025-10-09 22:43 ` Michael Lohmann
2025-10-13 9:57 ` Submitted patches for "assume unsafe" Michael Lohmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).