Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions controller/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ func GetAllChannels(c *gin.Context) {
typeFilter = t
}
}
// group filter
groupFilter := c.Query("group")

var total int64

Expand Down Expand Up @@ -114,6 +116,11 @@ func GetAllChannels(c *gin.Context) {
if typeFilter >= 0 && ch.Type != typeFilter {
continue
}
if groupFilter != "" && groupFilter != "null" {
if !strings.Contains(","+ch.Group+",", ","+groupFilter+",") {
continue
}
}
filtered = append(filtered, ch)
}
channelData = append(channelData, filtered...)
Expand All @@ -129,6 +136,14 @@ func GetAllChannels(c *gin.Context) {
} else if statusFilter == 0 {
baseQuery = baseQuery.Where("status != ?", common.ChannelStatusEnabled)
}
if groupFilter != "" && groupFilter != "null" {
if common.UsingMySQL {
baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
} else {
// SQLite, PostgreSQL
baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+groupFilter+",%")
}
}
Comment on lines +139 to +146
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify commonGroupCol is defined and check usage patterns

echo "=== Checking if commonGroupCol is defined in model/main.go ==="
rg -n "commonGroupCol" model/main.go

echo -e "\n=== Finding other usages of commonGroupCol in the codebase ==="
rg -n "commonGroupCol" --type=go -C3

echo -e "\n=== Finding raw SQL references to 'group' column (potential violations) ==="
rg -nP '(CONCAT|WHERE).*[`"]group[`"]' --type=go -C2

Repository: QuantumNous/new-api

Length of output: 8077


Use commonGroupCol variable for the reserved-word column per coding guidelines.

The group column is a SQL reserved word. The coding guidelines require using the commonGroupCol variable from model/main.go instead of hardcoding column quoting. This same pattern is correctly implemented in model/channel.go lines 370–379 and 862–871 using commonGroupCol, ensuring consistent handling across all database dialects.

The fix applies the pattern already established elsewhere in the codebase:

Proposed fix
 	if groupFilter != "" && groupFilter != "null" {
 		if common.UsingMySQL {
-			baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
+			baseQuery = baseQuery.Where("CONCAT(',', "+model.commonGroupCol+", ',') LIKE ?", "%,"+groupFilter+",%")
 		} else {
 			// SQLite, PostgreSQL
-			baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+groupFilter+",%")
+			baseQuery = baseQuery.Where("(',' || "+model.commonGroupCol+" || ',') LIKE ?", "%,"+groupFilter+",%")
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel.go` around lines 139 - 146, The code hardcodes the
reserved column name "group" when filtering by groupFilter; replace those
literals with the shared variable commonGroupCol (as used in model/channel.go)
so quoting/concatenation is consistent across dialects: update the branch that
checks common.UsingMySQL and the else branch to use commonGroupCol in the
CONCAT/|| expressions and keep the same LIKE pattern logic applied to
baseQuery.Where, referencing baseQuery, groupFilter, and common.UsingMySQL.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if SearchChannels/model layer has same LIKE pattern without escaping

echo "=== Checking model.SearchChannels for group LIKE pattern ==="
rg -n "LIKE.*group" model/ --type=go -C5

echo -e "\n=== Searching for LIKE escape utilities in common package ==="
rg -n "EscapeLike|escapeLike|LIKE.*escape" common/ --type=go -C3

echo -e "\n=== Finding other LIKE patterns with user input in controller ==="
rg -nP 'LIKE.*\%.*\+.*\+' controller/ --type=go -C2

Repository: QuantumNous/new-api

Length of output: 2636


🏁 Script executed:

#!/bin/bash
# Search for all LIKE patterns with user input concatenation in the codebase
echo "=== Finding all LIKE patterns with potential unescaped user input ==="
rg -n 'LIKE.*\%.*\+' controller/ model/ --type=go -C3 | head -100

echo -e "\n=== Check if keyword, model parameters are also vulnerable ==="
rg -n '"keyword"|"model"|"group"' controller/channel.go model/channel.go --type=go -B2 -A2 | grep -E "(keyword|model|group)" | head -20

echo -e "\n=== Check if there are any existing string escaping utilities ==="
rg -n "ReplaceAll|Escape|escape" common/ --type=go | grep -i "like\|sql\|escape" | head -20

Repository: QuantumNous/new-api

Length of output: 1208


🏁 Script executed:

#!/bin/bash
# Find all LIKE patterns with string concatenation (simpler approach)
echo "=== All LIKE query patterns in controller/channel.go ==="
rg -n 'LIKE' controller/channel.go --type=go -B2 -A2

echo -e "\n=== All LIKE query patterns in model/channel.go ==="
rg -n 'LIKE' model/channel.go --type=go -B2 -A2

echo -e "\n=== Check if groupFilter is used elsewhere ==="
rg -n 'groupFilter' controller/ --type=go -C2

echo -e "\n=== Verify if ESCAPE clause is properly supported ==="
rg -n 'ESCAPE' . --type=go -C2

Repository: QuantumNous/new-api

Length of output: 5398


🏁 Script executed:

#!/bin/bash
# Check if sanitizeLikePattern is exported (uppercase) and could be reused
echo "=== Check sanitizeLikePattern function definition ==="
rg -n 'func sanitizeLikePattern' model/token.go --type=go -A15

echo -e "\n=== Check how it's used in token.go ==="
rg -n 'sanitizeLikePattern' model/token.go --type=go -B2 -A2

echo -e "\n=== Check if function is called from controller ==="
rg -n 'sanitizeLikePattern' controller/ --type=go

echo -e "\n=== Check the full context of the vulnerable code in controller ==="
sed -n '130,150p' controller/channel.go

Repository: QuantumNous/new-api

Length of output: 2288


Escape SQL LIKE wildcards in groupFilter to prevent unintended pattern matching.

The groupFilter value is concatenated directly into the LIKE pattern without escaping SQL wildcard characters (% and _). If groupFilter contains these characters, they will be interpreted as wildcards rather than literal characters. For example, filtering by "admin%" would incorrectly match "admin", "administrator", and "admin_team".

A similar vulnerability exists in model/channel.go (lines 379, 871) with the keyword, model, and group parameters. The codebase already defines a sanitization pattern in model/token.go using ! as the ESCAPE character, which should be adopted here for consistency.

Suggested fix
+	// Escape LIKE wildcards in groupFilter
+	escapedGroupFilter := strings.ReplaceAll(strings.ReplaceAll(groupFilter, "!", "!!"), "_", "!_")
+
 	if groupFilter != "" && groupFilter != "null" {
 		if common.UsingMySQL {
-			baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
+			baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ? ESCAPE '!'", "%,"+escapedGroupFilter+",%")
 		} else {
 			// SQLite, PostgreSQL
-			baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+escapedGroupFilter+",%")
+			baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ? ESCAPE '!'", "%,"+escapedGroupFilter+",%")
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel.go` around lines 139 - 146, The LIKE pattern concatenation
using groupFilter is vulnerable to wildcard interpretation; update the code that
builds the pattern (the baseQuery.Where calls that use groupFilter) to first
escape '!' then '%' and '_' in groupFilter (e.g. replace "!" -> "!!", "%" ->
"!%", "_" -> "!_"), then use the escaped value in the bound parameter and append
" ESCAPE '!'" to the SQL fragment; do this for both MySQL and non-MySQL branches
(the CONCAT/(',' || "group" || ',') patterns) and apply the same escaping
strategy to the other affected call sites in model/channel.go that use keyword,
model, and group parameters so all LIKE queries use the same escape character
and escaped inputs.


baseQuery.Count(&total)

Expand Down