From: Derrick Stolee <email@example.com>
To: "Git Mailing List" <firstname.lastname@example.org>,
"Junio C Hamano" <email@example.com>,
"Taylor Blau" <firstname.lastname@example.org>,
"Emily Shaffer" <email@example.com>,
"Glen Choo" <firstname.lastname@example.org>,
"Ævar Arnfjörð Bjarmason" <email@example.com>,
"Christian Couder" <firstname.lastname@example.org>
Subject: [Discussion] What is Git's Security Boundary?
Date: Tue, 26 Apr 2022 13:00:27 -0400 [thread overview]
Message-ID: <email@example.com> (raw)
I've been having a few discussions internally and externally with folks
about the 2.35.2 release and the safe.directory config value. After
stumbling a little with a too-technical proposal, I (along with Taylor)
figured out that I was jumping into "solutions" mode without first talking
about the problem and agreeing on common language there.
Specifically, the issue at the root of CVE-2022-24765  is that a
machine can have an "untrusted" Git repository on-disk. The actual exploit
uses hooks as an attack vector. The protection we put in place was the
safe.directory config key, which is only read out of "protected" config
I had started going down a rabbit hole of additional ways to harden our
security stance using this concept of "protected" config files, but that
I'm hoping to start a conversation in this thread about "What is Git's
security boundary?" so we can have an established base to work from for
future security incidents or protections.
The only documentation I could find is our security policy , but that
doesn't try to define this boundary. Recent discussions on the config-
based hooks have also talked about the security boundary .
What is Git's Security Boundary?
From my discussions, I've seen two different perspectives on Git's
1. When Git interacts with another _machine_ over a protocol, then Git
must be hardened against malicious actors across that protocol. Git
expects data on disk from that point on to be created by "trusted"
actors. Any files checked out from a remote source are expected to
be inspected by the user before they are used.
2. Users expect Git commands, especially those that do not communicate
over a network, to be as safe to use as a text editor. If there is
a realistic vector where an unprivileged actor with access to a
mounted disk can create a malicious repo on disk and convince another
user to run a Git command, then Git should protect against this attack
to the best of its ability.
The choice here is not an either-or: (1) is obviously an important case to
handle. The question is "how much of (2) are we responsible for?" I admit
that this area has no strict boundary, but instead must be inspected on a
case-by-case basis. The level of social engineering must be taken into
account. It is probably clear that we shouldn't protect against someone
who was tricked into running `git bisect run rm -rf /*` but most cases
require more inspection.
The case that came about in the recent security release had an attack
vector that is identical to using a shared repository, which is a valid
use case. Hence, the `safe.directory` config value was created. Users
using shared repositories like this (now marked with `safe.directory`) are
susceptible to someone modifying the repository-local config in a
repository they have been using without issue. This allows an actor with
access to one user's credentials to gain access to other users on that
machine, spreading their access. The ability to change the executable run
by Git via local config is the critical piece of this attack.
Example: Out of security boundary: improper filesystem permissions
It can be helpful to include a case of something that is outside of our
security boundary. In particular, if the machine has filesystem
permissions set improperly (and different than the default upon install),
then the following things can happen:
1. An attacker could replace the Git executable.
2. An attacker could modify `~/.gitconfig` to change config and have Git
execute arbitrary code.
3. An attacker could modify `~/.bashrc` (or equivalents) to change
environment variables such as the `PATH` or anything else.
Hopefully we can all agree that if the machine is in such a state, then
there is nothing we can do and would not call this a vulnerability _in Git_.
Example: Out of security boundary: "clone and make"
A well-established example is the case where a combination of social
engineering and lack of user care lead to an attack. This is most
commonly of the form of "clone this repo, go into it and run 'make'".
Building code right after cloning is a common workflow for developers,
but that does not mean that this is an attack. Running content that
could execute arbitrary code on your machine should always be checked
This "attack" vector is considered outside of the boundary because of
the social engineering aspect (the attacker needs you to clone the
repo _and_ run something inside it) and the lack of care by the user.
The user has ample opportunity to check what they are about to do
before running that second execution step.
The other side of this situation is this: there is nothing Git can do.
Once Git has cloned the data it was asked to clone, no part of this
attack uses Git itself. There is no opportunity to intervene. Git is
doing exactly what it is asked to do: nothing less _and nothing more_.
Question: Is there a better way to describe the boundary?
Please submit your attempts to clarify the boundary in replies.
Question: Is "protected" config _really_ more trustworthy?
This leads to an interesting question: Do we think that `~/.gitconfig`
and `/etc/gitconfig` are "more trustworthy" than `.git/config`?
I think that if an attacker has access to write to system or global config,
then they have access to do more harm without Git. On the other hand,
local config overrides the other config values, so local config can "unset"
any potentially-malicious values in system and global config. I don't
think such "defensive config" is common.
Example Security Boundary Question: Unprotected Config and Executing Code
We have a lot of ways of executing external code from within Git. This is
a key extensibility feature for customizing Git functionality. One way to
do this is to create executable files in the $GIT_DIR/hooks/ directory.
Git will discover these hooks and run them at the appropriate times.
There are also many config options that specify external commands to run:
* `core.fsmonitor=<path>` is executed before scanning the worktree for
created or modified files.
* `core.editor` specifies an editor when writing commit messages, among
other user-input scenarios.
* `credential.helper` specifies an external tool to assist with connecting
to a remote repository.
* `uploadPack.packObjectsHook` chooses an alternative for `git pack-objects`
during `git upload-pack`.
The list is actually quite long. This last one, `uploadPack.packObjectsHook`
_does_ do a check for protected config: it does not allow its value to
come from repository-local config.
However, most of these options really do want to have customization on a
per-repository basis, hence this proliferation of config options and
local hook directories.
I'm concerned that as long as we allow arbitrary execution to happen based
on repository-local data, we will always have security risks in Git. For
that reason, I'm interested in exploring ways to change how we execute
code externally, even if it means we would (eventually) need to introduce
a breaking change.
The idea would be to allow repository-local customization by selecting
from a list of "installed" executables. The list of "installed"
executables comes from protected config (and the Git binary itself).
The plan I would like to put forward is to restrict all external execution
to be from one of these sources:
1. Specified in system config (`/etc/gitconfig`).
2. Specified in global config (`~/.gitconfig`).
3. An allow-list of known tools, on $PATH (e.g. `vim`).
Such a change would be a major one, and would require changing a lot of
existing code paths. In particular, this completely removes the
functionality of the `$GIT_DIR/hooks/` directory in favor of a config-
based approach. This would require wide communication before pulling all
support for the old way, and likely a 3.0 version designation. After the
old hook mechanism is removed, the "safe.directory" protection from 2.35.2
would no longer be needed.
At minimum, in the short term, this would affect the proposed design of
I think this is a good example to think about at a high level before going
into the technical details. We can use it to test any proposed security
boundary definitions to see if it lands on one side or another. Here are
1. These config-based executables cannot be set in a full repository by
a "git clone" operation.
2. These config-based executables can be set in an embedded bare
repository, but the user needs to move deeper into the repository for
that to have any affect. This leads to some amount of social engineering
being involved in the attack. See  for recent discussion on this.
3. If users are sharing a common Git repository, then if an attacker gains
control of one user's account, they can use the shared repository as an
attack vector to gain control of the other users' accounts. For this
case, do we consider the "safe.directory" config as an indicator of
"I trust this repo and all users that can access it _in perpetuity_" or
instead "I need to use this repo, even though it is owned by someone
4. Git's dedication to backwards compatibility might prevent any attempt
to change how hooks are specified or config can be used to customize
5. The technical challenge of converting all possible execution paths may
be too daunting to ever feel the project is "complete" and be able to
confidently say "Git is safe from these kinds of attacks".
I look forward to hearing from the community about this topic. There are
so many things to think about in this space, and I hope that a lot of
voices can share their perspectives here.
Please collect any action items here at the end. I would love to add a
doc to the Git tree that summarizes our conclusions here, even if it is
only a start to our evolving security boundary.
next reply other threads:[~2022-04-26 17:00 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-26 17:00 Derrick Stolee [this message]
2022-05-16 14:13 ` [Discussion] What is Git's Security Boundary? Derrick Stolee
2022-05-16 14:38 ` rsbecker
2022-05-20 17:23 ` Derrick Stolee
2022-05-17 12:55 ` Ævar Arnfjörð Bjarmason
2022-05-20 17:53 ` Derrick Stolee
2022-05-21 10:22 ` Ævar Arnfjörð Bjarmason
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).