From 97078b96cfcaeeed7ed82cc51a6822d906e5e0e3 Mon Sep 17 00:00:00 2001 From: bircni Date: Tue, 7 Jul 2026 19:35:21 +0200 Subject: [PATCH] fix(mirror): disable HTTP redirects on pull mirror sync (#38320) Pull mirror sync ran `git fetch` / `remote update` / `remote prune` without disabling HTTP redirects. A mirror remote that later starts redirecting to an otherwise-blocked or internal address could be used as an SSRF/exfiltration vector on scheduled syncs, bypassing the allow/block validation applied at migration time. This sets `http.followRedirects=false` on all three remote-contacting commands in the pull mirror path, matching the existing guard already present on the clone path. --- services/mirror/mirror_pull.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 5a9e546d56..615b1a6ae1 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -71,7 +71,8 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error } func pruneBrokenReferences(ctx context.Context, m *repo_model.Mirror, gitRepo gitrepo.Repository, timeout time.Duration) error { - cmd := gitcmd.NewCommand("remote", "prune").AddDynamicArguments(m.GetRemoteName()).WithTimeout(timeout) + // Never follow HTTP redirects, see cmdFetch in runSync. + cmd := gitcmd.NewCommand("remote", "prune").AddConfig("http.followRedirects", "false").AddDynamicArguments(m.GetRemoteName()).WithTimeout(timeout) stdout, _, pruneErr := gitrepo.RunCmdString(ctx, gitRepo, cmd) if pruneErr != nil { // sanitize the output, since it may contain the remote address, which may contain a password @@ -119,7 +120,9 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu // use fetch but not remote update because git fetch support --tags but remote update doesn't cmdFetch := func() *gitcmd.Command { - cmd := gitcmd.NewCommand("fetch", "--tags") + // Never follow HTTP redirects: a mirror remote that later starts redirecting to an + // otherwise-blocked address would be an SSRF/exfiltration vector on scheduled syncs. + cmd := gitcmd.NewCommand("fetch", "--tags").AddConfig("http.followRedirects", "false") if m.EnablePrune { cmd.AddArguments("--prune") } @@ -200,7 +203,8 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu } cmdRemoteUpdatePrune := func() *gitcmd.Command { - return gitcmd.NewCommand("remote", "update", "--prune"). + // Never follow HTTP redirects, see cmdFetch above. + return gitcmd.NewCommand("remote", "update", "--prune").AddConfig("http.followRedirects", "false"). AddDynamicArguments(m.GetRemoteName()).WithTimeout(timeout).WithEnv(envs) }