From f64ee9d1edf08bce6ced443c62809a00445853b2 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 21 Aug 2026 19:41:16 -0700 Subject: [PATCH] fix(migrations): bound OneDev version responses (#39024) (#39033) Backport #39024 by @bircni Limit OneDev version responses before parsing so a remote server cannot make a migration retain an unbounded response. Co-authored-by: bircni --- services/migrations/onedev.go | 10 ++++++++-- services/migrations/onedev_test.go | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/services/migrations/onedev.go b/services/migrations/onedev.go index 262b12cf1c2..54ad5b8fbb0 100644 --- a/services/migrations/onedev.go +++ b/services/migrations/onedev.go @@ -21,7 +21,10 @@ import ( "github.com/hashicorp/go-version" ) -const OneDevRequiredVersion = "12.0.1" +const ( + OneDevRequiredVersion = "12.0.1" + maxOneDevVersionResponseSize = 1024 +) var ( _ base.Downloader = &OneDevDownloader{} @@ -137,10 +140,13 @@ func (d *OneDevDownloader) callAPI(ctx context.Context, endpoint string, paramet // special case to read OneDev server version, which is not valid JSON if presult, ok := result.(**version.Version); ok { - bytes, err := io.ReadAll(resp.Body) + bytes, err := io.ReadAll(io.LimitReader(resp.Body, maxOneDevVersionResponseSize+1)) if err != nil { return err } + if len(bytes) > maxOneDevVersionResponseSize { + return fmt.Errorf("OneDev server version response exceeds %d bytes", maxOneDevVersionResponseSize) + } vers, err := version.NewVersion(string(bytes)) if err != nil { return err diff --git a/services/migrations/onedev_test.go b/services/migrations/onedev_test.go index 6132c72d5a9..eb2e47800d9 100644 --- a/services/migrations/onedev_test.go +++ b/services/migrations/onedev_test.go @@ -4,6 +4,9 @@ package migrations import ( + "bytes" + "net/http" + "net/http/httptest" "net/url" "os" "path/filepath" @@ -14,9 +17,24 @@ import ( "gitea.dev/models/unittest" base "gitea.dev/modules/migration" + "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" ) +func TestOneDevVersionResponseSizeLimit(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(bytes.Repeat([]byte("1"), maxOneDevVersionResponseSize+1)) + })) + defer server.Close() + + baseURL, err := url.Parse(server.URL) + assert.NoError(t, err) + download := &OneDevDownloader{baseURL: baseURL, client: server.Client()} + var version *version.Version + err = download.callAPI(t.Context(), "/~api/version/server", nil, &version) + assert.Error(t, err) +} + func TestOneDevDownloadRepo(t *testing.T) { liveMode := os.Getenv("ONEDEV_LIVE") != ""