CVE-2023-46575 (published 2023-11-24T14:15Z)

A SQL injection vulnerability exists in Meshery prior to version v0.6.179, enabling a remote attacker to retrieve sensitive information and execute arbitrary code through the “order” parameter

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-89
cwe_name: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/meshery/meshery
commit_details: repo_url: https://github.com/meshery/meshery
author: phant0ms
author_date: 2023-11-16 11:39:54+08:00
msg: ## Add "order by" parameter filter

## and export SanitizeOrderInput function

Signed-off-by: phant0ms <ph1nt0ms@gmail.com>
repository: repo_url: https://github.com/meshery/meshery
repo_name: meshery/meshery
description: Meshery, the cloud native manager
repo_language: JavaScript
owner: meshery
file_changes: filename: database_handlers.go
change_type: ModificationType.MODIFY
diff: @@ -73,6 +73,7 @@ func (h *Handler) GetSystemDatabase(w http.ResponseWriter, r *http.Request, _ *m
 	if offset != 0 {
 		tableFinder = tableFinder.Offset(offset)
 	}
+	order = models.SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 	if order != "" {
 		if sort == "desc" {
 			tableFinder = tableFinder.Order(clause.OrderByColumn{Column: clause.Column{Name: order}, Desc: true})

programming_language: Go
filename: meshery_application_persister.go
change_type: ModificationType.MODIFY
diff: @@ -24,7 +24,7 @@ type MesheryApplicationPage struct {
 
 // GetMesheryApplications returns all of the applications
 func (maap *MesheryApplicationPersister) GetMesheryApplications(search, order string, page, pageSize uint64, updatedAfter string) ([]byte, error) {
-	order = sanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
+	order = SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 
 	if order == "" {
 		order = "updated_at desc"

programming_language: Go
filename: meshery_filter_persister.go
change_type: ModificationType.MODIFY
diff: @@ -28,7 +28,7 @@ type MesheryFilterPage struct {
 // GetMesheryFilters returns all of the 'private' filters. Though private has no meaning here since there is only
 // one local user. We make this distinction to be consistent with the remote provider
 func (mfp *MesheryFilterPersister) GetMesheryFilters(search, order string, page, pageSize uint64, visibility []string) ([]byte, error) {
-	order = sanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
+	order = SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 
 	if order == "" {
 		order = "updated_at desc"
@@ -65,7 +65,7 @@ func (mfp *MesheryFilterPersister) GetMesheryFilters(search, order string, page,
 // GetMesheryCatalogFilters returns all of the published filters
 func (mfp *MesheryFilterPersister) GetMesheryCatalogFilters(page, pageSize, search, order string) ([]byte, error) {
 	var err error
-	order = sanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
+	order = SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 
 	if order == "" {
 		order = "updated_at desc"

programming_language: Go
filename: meshery_k8scontext_persister.go
change_type: ModificationType.MODIFY
diff: @@ -25,7 +25,7 @@ type MesheryK8sContextPage struct {
 
 // GetMesheryK8sContexts returns all of the contexts
 func (mkcp *MesheryK8sContextPersister) GetMesheryK8sContexts(search, order string, page, pageSize uint64) ([]byte, error) {
-	order = sanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
+	order = SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 
 	if order == "" {
 		order = "updated_at desc"

programming_language: Go
filename: meshery_pattern_persister.go
change_type: ModificationType.MODIFY
diff: @@ -29,7 +29,7 @@ type MesheryPatternPage struct {
 // GetMesheryPatterns returns all of the 'private' patterns. Though private has no meaning here since there is only
 // one local user. We make this distinction to be consistent with the remote provider
 func (mpp *MesheryPatternPersister) GetMesheryPatterns(search, order string, page, pageSize uint64, updatedAfter string, visibility []string) ([]byte, error) {
-	order = sanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
+	order = SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 
 	if order == "" {
 		order = "updated_at desc"
@@ -65,7 +65,7 @@ func (mpp *MesheryPatternPersister) GetMesheryPatterns(search, order string, pag
 // GetMesheryCatalogPatterns returns all of the published patterns
 func (mpp *MesheryPatternPersister) GetMesheryCatalogPatterns(page, pageSize, search, order string) ([]byte, error) {
 	var err error
-	order = sanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
+	order = SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 
 	if order == "" {
 		order = "updated_at desc"

programming_language: Go
filename: pattern_resource_persister.go
change_type: ModificationType.MODIFY
diff: @@ -57,7 +57,7 @@ func (prp *PatternResourcePersister) GetPatternResourceByAttributes(name, namesp
 }
 
 func (prp *PatternResourcePersister) GetPatternResources(search, order, name, namespace, typ, oamType string, page, pageSize uint64) (*PatternResourcePage, error) {
-	order = sanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
+	order = SanitizeOrderInput(order, []string{"created_at", "updated_at", "name"})
 
 	if order == "" {
 		order = "updated_at desc"
@@ -106,7 +106,7 @@ func (prp *PatternResourcePersister) Exists(name, namespace, typ, oamType string
 
 	prp.DB.
 		Raw(`
-	SELECT 
+	SELECT
 		EXISTS(SELECT 1 FROM pattern_resources WHERE name = ? AND namespace = ? AND type = ? AND oam_type = ? AND deleted = false) AS "found"`,
 			name,
 			namespace,

programming_language: Go
filename: performance_profile_persister.go
change_type: ModificationType.MODIFY
diff: @@ -24,7 +24,7 @@ type PerformanceProfilePage struct {
 
 // GetPerformanceProfiles returns all of the performance profiles
 func (ppp *PerformanceProfilePersister) GetPerformanceProfiles(_, search, order string, page, pageSize uint64) ([]byte, error) {
-	order = sanitizeOrderInput(order, []string{"updated_at", "created_at", "name", "last_run"})
+	order = SanitizeOrderInput(order, []string{"updated_at", "created_at", "name", "last_run"})
 	if order == "" {
 		order = "updated_at desc"
 	}

programming_language: Go
filename: sql-utils.go
change_type: ModificationType.MODIFY
diff: @@ -12,16 +12,16 @@ import (
 	"github.com/spf13/viper"
 )
 
-// sanitizeOrderInput takes in the "order by" query, a validColums
+// SanitizeOrderInput takes in the "order by" query, a validColums
 // string slice and returns a sanitized query
 //
 // it will allow to run order by query only on the columns that are present
 // in the validColumns string slice, if any other column is requested in the
 // query then it will be IGNORED and an empty query would be returned instead
 //
-// sanitizeOrderInput also expects the query to be no longer than two words, that is
+// SanitizeOrderInput also expects the query to be no longer than two words, that is
 // the query may look like "updated_at DESC" or "name ASC"
-func sanitizeOrderInput(order string, validColumns []string) string {
+func SanitizeOrderInput(order string, validColumns []string) string {
 	parsedOrderStr := strings.Split(order, " ")
 	if len(parsedOrderStr) != 2 {
 		return ""

programming_language: Go