From 2cadbbd6bb17bc08419358a2369d6d8e4e2c71c0 Mon Sep 17 00:00:00 2001 From: Carter Brainerd Date: Thu, 3 Sep 2026 12:59:05 -0400 Subject: [PATCH] fix/batches: reject Git metadata in repository archives --- internal/batches/workspace/bind_workspace.go | 9 ++++++++ .../batches/workspace/bind_workspace_test.go | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/internal/batches/workspace/bind_workspace.go b/internal/batches/workspace/bind_workspace.go index 3519e6f13c..c76a30ba60 100644 --- a/internal/batches/workspace/bind_workspace.go +++ b/internal/batches/workspace/bind_workspace.go @@ -206,6 +206,15 @@ func unzip(ctx context.Context, zipFile, dest string) error { return fmt.Errorf("%s: illegal file path", fpath) } + relativePath, err := filepath.Rel(dest, fpath) + if err != nil { + return err + } + firstPathElement, _, _ := strings.Cut(relativePath, string(os.PathSeparator)) + if strings.EqualFold(firstPathElement, ".git") { + return fmt.Errorf("%s: repository archive contains Git metadata", f.Name) + } + if f.FileInfo().IsDir() { if err := mkdirAll(dest, f.Name, 0777); err != nil { return err diff --git a/internal/batches/workspace/bind_workspace_test.go b/internal/batches/workspace/bind_workspace_test.go index 5fe05c2edf..c120eb0c11 100644 --- a/internal/batches/workspace/bind_workspace_test.go +++ b/internal/batches/workspace/bind_workspace_test.go @@ -143,6 +143,29 @@ func TestDockerBindWorkspaceCreator_Create(t *testing.T) { }) } +func TestUnzipRejectsGitMetadata(t *testing.T) { + for _, name := range []string{ + ".git/config", + ".git/hooks/pre-commit", + "dir/../.git/config", + ".GIT/config", + } { + t.Run(name, func(t *testing.T) { + archivePath := zipUpFiles(t, t.TempDir(), map[string]string{name: "malicious"}) + dest := t.TempDir() + + err := unzip(context.Background(), archivePath, dest) + if err == nil || !strings.Contains(err.Error(), "repository archive contains Git metadata") { + t.Fatalf("expected Git metadata error, got %v", err) + } + + if _, err := os.Stat(filepath.Join(dest, ".git")); !os.IsNotExist(err) { + t.Fatalf("expected .git not to be extracted, got %v", err) + } + }) + } +} + func TestDockerBindWorkspace_ApplyDiff(t *testing.T) { // Create a zip file for all the other tests to use. fakeFilesTmpDir := t.TempDir()