diff --git a/backend/repository/recipient.go b/backend/repository/recipient.go index a7fbb5b..d247bee 100644 --- a/backend/repository/recipient.go +++ b/backend/repository/recipient.go @@ -3,6 +3,7 @@ package repository import ( "context" "fmt" + "slices" "strconv" "time" @@ -383,6 +384,10 @@ func (r *Recipient) GetOrphaned( // apply query args for sorting/pagination if provided if options.QueryArgs != nil { if options.QueryArgs.OrderBy != "" { + // validate orderBy against allowlist + if !slices.Contains(allowdRecipientColumns, options.QueryArgs.OrderBy) { + return result, fmt.Errorf("invalid order by column: %s", options.QueryArgs.OrderBy) + } direction := "ASC" if options.QueryArgs.Desc { direction = "DESC" diff --git a/backend/vo/queryParams.go b/backend/vo/queryParams.go index e26466e..b84d188 100644 --- a/backend/vo/queryParams.go +++ b/backend/vo/queryParams.go @@ -60,12 +60,15 @@ func (q *QueryArgs) DefaultSortBy(column string) { } } -// RemapOrderBy remaps the order by column +// RemapOrderBy remaps the order by column using the provided mapping. +// if the column is not found in the mapping, it is cleared to prevent SQL injection. func (q *QueryArgs) RemapOrderBy(m map[string]string) { if q.OrderBy == "" { return } if v, ok := m[q.OrderBy]; ok { q.OrderBy = v + } else { + q.OrderBy = "" } }