diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-06-28 10:12:19 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-06-28 11:48:25 +0300 |
commit | 0ef2a43087a702169fb0ab98776b4260a51ad455 (patch) | |
tree | 0437f1f62deab1ee2137bccffeebf979fae0bfca | |
parent | 549cb32c28b74beba0b56d158150231f251c24c1 (diff) |
repository: Fix clone credentials leaking via command line argumentspks-create-repo-from-url-leaking-credentials
On Linux systems, users can by default observe all command line
arguments of processes that may not even be owned by the same user by
inspecting `/proc/${PID}/cmdline`. This means that we mustn't ever put
any credentials in command line arguments given that unprivileged users
can easily sniff them out. Instead, we typically use the environment to
place credentials, which by default is not readable by any other users.
While we do this in most cases, we don't in `CreateRepositoryFromURL()`.
This RPC uses `cloneFromURLCommand()`, which seemingly knows that it's
bad to put credentials on the command line and thus strips them from the
URL already. But afterwards it goes out of its way to put them on the
command line anyway by creating a set of `http.extraHeader` config
options that are passed to git-clone(1) via the `-c` switch.
Fix this by using `git.WithConfigEnv()` instead of `git.WithConfig()`,
which puts the credentials into the environment instead of the command
line.
Changelog: fixed
-rw-r--r-- | internal/gitaly/service/repository/create_repository_from_url.go | 2 | ||||
-rw-r--r-- | internal/gitaly/service/repository/create_repository_from_url_test.go | 14 |
2 files changed, 11 insertions, 5 deletions
diff --git a/internal/gitaly/service/repository/create_repository_from_url.go b/internal/gitaly/service/repository/create_repository_from_url.go index 8c0662fc1..f7fd9b853 100644 --- a/internal/gitaly/service/repository/create_repository_from_url.go +++ b/internal/gitaly/service/repository/create_repository_from_url.go @@ -68,7 +68,7 @@ func (s *server) cloneFromURLCommand( Flags: cloneFlags, Args: []string{u.String(), repositoryFullPath}, }, - append(opts, git.WithConfig(config...))..., + append(opts, git.WithConfigEnv(config...))..., ) } diff --git a/internal/gitaly/service/repository/create_repository_from_url_test.go b/internal/gitaly/service/repository/create_repository_from_url_test.go index 6449a75c3..5fdd93ccb 100644 --- a/internal/gitaly/service/repository/create_repository_from_url_test.go +++ b/internal/gitaly/service/repository/create_repository_from_url_test.go @@ -203,7 +203,7 @@ func TestServer_CloneFromURLCommand(t *testing.T) { url: fmt.Sprintf("https://%s:%s@192.0.2.1/secretrepo.git", user, password), token: "", expectedAuthHeader: fmt.Sprintf( - "http.extraHeader=Authorization: Basic %s", + "Authorization: Basic %s", base64.StdEncoding.EncodeToString([]byte("example_user:pass!?@")), ), }, @@ -212,7 +212,7 @@ func TestServer_CloneFromURLCommand(t *testing.T) { url: "https://192.0.2.1/secretrepo.git", token: "some-token", expectedAuthHeader: fmt.Sprintf( - "http.extraHeader=Authorization: %s", "some-token", + "Authorization: %s", "some-token", ), }, } { @@ -240,12 +240,18 @@ func TestServer_CloneFromURLCommand(t *testing.T) { args := cmd.Args() require.Contains(t, args, "--bare") require.Contains(t, args, "https://192.0.2.1/secretrepo.git") - require.Contains(t, args, tc.expectedAuthHeader) - require.Contains(t, args, "http.extraHeader=Host: www.example.com") for _, arg := range args { require.NotContains(t, arg, user) require.NotContains(t, arg, password) + require.NotContains(t, arg, tc.expectedAuthHeader) } + + require.Subset(t, cmd.Env(), []string{ + "GIT_CONFIG_KEY_0=http.extraHeader", + "GIT_CONFIG_VALUE_0=" + tc.expectedAuthHeader, + "GIT_CONFIG_KEY_1=http.extraHeader", + "GIT_CONFIG_VALUE_1=Host: www.example.com", + }) }) } } |