From 7e7e778d4945ffc2a5ca82c2be0a6ec1036f189f Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 24 Feb 2026 20:38:12 +0100 Subject: [PATCH] fix(db): validate table names and quote identifiers in raw SQL --- pkg/db/dump.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/db/dump.go b/pkg/db/dump.go index 4fb214497..8781dba9d 100644 --- a/pkg/db/dump.go +++ b/pkg/db/dump.go @@ -18,6 +18,8 @@ package db import ( "encoding/json" + "fmt" + "regexp" "strings" "code.vikunja.io/api/pkg/log" @@ -25,6 +27,15 @@ import ( "xorm.io/xorm/schemas" ) +var validTableName = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`) + +func validateTableName(table string) error { + if !validTableName.MatchString(table) { + return fmt.Errorf("invalid table name: %q", table) + } + return nil +} + // Dump dumps all database tables func Dump() (data map[string][]byte, err error) { tables, err := x.DBMetas() @@ -50,6 +61,10 @@ func Dump() (data map[string][]byte, err error) { // Restore restores a table with all its entries func Restore(table string, contents []map[string]interface{}) (err error) { + if err := validateTableName(table); err != nil { + return err + } + if _, err := x.IsTableExist(table); err != nil { return err } @@ -90,7 +105,7 @@ func Restore(table string, contents []map[string]interface{}) (err error) { if Type() == schemas.POSTGRES { idSequence := table + "_id_seq" - _, err = x.Query("SELECT setval('" + idSequence + "', COALESCE(MAX(id), 1) )") + _, err = x.Query(`SELECT setval('"` + idSequence + `"', COALESCE((SELECT MAX(id) FROM "` + table + `"), 1))`) if err != nil { log.Warningf("Could not reset id sequence for %s: %s", idSequence, err) err = nil @@ -102,12 +117,16 @@ func Restore(table string, contents []map[string]interface{}) (err error) { // RestoreAndTruncate removes all content from the table before restoring it from the contents map func RestoreAndTruncate(table string, contents []map[string]interface{}) (err error) { + if err := validateTableName(table); err != nil { + return err + } + if _, err := x.IsTableExist(table); err != nil { return err } if x.Dialect().URI().DBType == schemas.SQLITE { - if _, err := x.Query("DELETE FROM " + table); err != nil { + if _, err := x.Query(`DELETE FROM "` + table + `"`); err != nil { return err } } else {