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
167 changes: 167 additions & 0 deletions pkg/sanitize/nosql_detect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,170 @@ func TestNoSQLInjectionDetectorCustomOperators(t *testing.T) {
t.Fatalf("expected ErrNoSQLInjectionDetected, got %v", err)
}
}

func TestNoSQLInjectionDetectorEdgeCases(t *testing.T) {
detector, err := NewNoSQLInjectionDetector()
if err != nil {
t.Fatalf("expected detector, got %v", err)
}

tests := []struct {
name string
input string
wantError bool
}{
// Dollar sign at end of string
{
name: "dollar at end of string",
input: "price$",
wantError: false,
},
{
name: "dollar at end after text",
input: "total_usd$",
wantError: false,
},
// Dollar sign followed by non-alphabetic characters
{
name: "dollar followed by digit",
input: "$123",
wantError: false,
},
{
name: "dollar followed by special char",
input: "$@#%",
wantError: false,
},
{
name: "dollar followed by space",
input: "$ ",
wantError: false,
},
{
name: "dollar followed by underscore",
input: "$_test",
wantError: false,
},
// Dollar sign followed by valid characters but not matching any operator
{
name: "dollar with unknown operator",
input: "$unknown",
wantError: false,
},
{
name: "dollar with non-operator word",
input: "$hello",
wantError: false,
},
{
name: "dollar with random letters",
input: "$xyz",
wantError: false,
},
// Operators at start of string
{
name: "operator at start",
input: "$ne",
wantError: true,
},
{
name: "operator at start with value",
input: "$where:true",
wantError: true,
},
// Operators after various delimiters
{
name: "operator after open brace",
input: "{$ne:null}",
wantError: true,
},
{
name: "operator after open bracket",
input: "[$in:[1,2]]",
wantError: true,
},
{
name: "operator after comma",
input: "a,$gt:5",
wantError: true,
},
{
name: "operator after colon",
input: "field:$lt:10",
wantError: true,
},
{
name: "operator after double quote",
input: `"$regex":"pattern"`,
wantError: true,
},
{
name: "operator after single quote",
input: `'$exists':true`,
wantError: true,
},
{
name: "operator after open paren",
input: "($or:[a,b])",
wantError: true,
},
{
name: "operator after whitespace",
input: " $and",
wantError: true,
},
{
name: "operator after newline",
input: "\n$nor",
wantError: true,
},
{
name: "operator after tab",
input: "\t$not",
wantError: true,
},
// Mixed cases - dollar not at boundary
{
name: "dollar in middle of word",
input: "price$value",
wantError: false,
},
{
name: "dollar after letter no boundary",
input: "a$ne",
wantError: false,
},
// Multiple operators
{
name: "multiple operators",
input: `{"$ne":1,"$gt":2}`,
wantError: true,
},
// Case sensitivity checks - operators are normalized to lowercase
{
name: "operator uppercase detected",
input: "$NE",
wantError: true,
},
{
name: "operator mixed case detected",
input: "$Ne",
wantError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := detector.Detect(tt.input)
if tt.wantError {
if err != ErrNoSQLInjectionDetected {
t.Errorf("expected ErrNoSQLInjectionDetected for input %q, got %v", tt.input, err)
}
} else {
if err != nil {
t.Errorf("expected no error for input %q, got %v", tt.input, err)
}
}
})
}
}
Loading