From 757f00910eaeb49f547aaec7953a855002d9e388 Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 20 Oct 2026 02:19:46 +0200 Subject: [PATCH] fix(migration): cap the entry count of vikunja export archives --- .../migration/vikunja-file/limits_test.go | 19 +++++++++++++++++++ pkg/modules/migration/vikunja-file/vikunja.go | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/pkg/modules/migration/vikunja-file/limits_test.go b/pkg/modules/migration/vikunja-file/limits_test.go index 2c629c82f..978041a12 100644 --- a/pkg/modules/migration/vikunja-file/limits_test.go +++ b/pkg/modules/migration/vikunja-file/limits_test.go @@ -222,6 +222,25 @@ func TestVikunjaFileLimits(t *testing.T) { assertTooLarge(t, err) }) + t.Run("entries outside files/ count against the entry cap", func(t *testing.T) { + setLimits(t, "256MB", "1GB", 2) + entries := []struct { + name string + content []byte + }{} + for i := range 4 { + entries = append(entries, struct { + name string + content []byte + }{name: fmt.Sprintf("e%d", i)}) + } + export := buildExportWithFiles(t, testLimitsDataJSON, entries) + + err := (&FileMigrator{}).ValidateFile(bytes.NewReader(export), int64(len(export))) + assertTooLarge(t, err) + assert.Contains(t, err.Error(), "many") + }) + t.Run("duplicate file ids are rejected", func(t *testing.T) { setLimits(t, "256MB", "1GB", 10000) export := buildExportWithFiles(t, testLimitsDataJSON, []struct { diff --git a/pkg/modules/migration/vikunja-file/vikunja.go b/pkg/modules/migration/vikunja-file/vikunja.go index 8a5650c26..b9b8a180b 100644 --- a/pkg/modules/migration/vikunja-file/vikunja.go +++ b/pkg/modules/migration/vikunja-file/vikunja.go @@ -304,6 +304,11 @@ func openArchive(file io.ReaderAt, size int64) (*zip.Reader, error) { func scanArchive(r *zip.Reader) (*archive, error) { log.Debugf(logPrefix+"Importing a zip file containing %d files", len(r.File)) + // files/ entries plus data.json, filters.json and VERSION + if int64(len(r.File)) > config.MigrationVikunjaFileMaxFiles.GetInt64()+3 { + return nil, &ErrVikunjaFileImportTooLarge{Reason: "it contains too many entries for migration.vikunjafile.maxfiles"} + } + a := &archive{storedFiles: make(map[int64]*zip.File)} var storedFileCount int64 for _, f := range r.File {