Skip to content

Commit f9555e3

Browse files
committed
add sql injection tests
1 parent a9736f5 commit f9555e3

File tree

3 files changed

+207
-1
lines changed

3 files changed

+207
-1
lines changed

tests/passed-tests.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,7 @@ BenchmarkScanSlice
379379
BenchmarkScanSlicePointer
380380
BenchmarkUpdate
381381
BenchmarkDelete
382+
TestRawQueryInjection
383+
TestWhereClauseInjection
384+
TestUpdateInjection
385+
TestFirstOrCreateInjection

tests/run-tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ echo "Processing tests from passed-tests.txt..."
4040
echo ""
4141

4242
# Read the file line by line
43-
while IFS= read -r line; do
43+
while IFS= read -r line || [[ -n "$line" ]]; do
4444
# Skip empty lines - keep them as is
4545
if [[ -z "$line" ]]; then
4646
echo "$line" >> "$temp_file"

tests/sql_injection_test.go

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
** Copyright (c) 2025 Oracle and/or its affiliates.
3+
**
4+
** The Universal Permissive License (UPL), Version 1.0
5+
**
6+
** Subject to the condition set forth below, permission is hereby granted to any
7+
** person obtaining a copy of this software, associated documentation and/or data
8+
** (collectively the "Software"), free of charge and under any and all copyright
9+
** rights in the Software, and any and all patent rights owned or freely
10+
** licensable by each licensor hereunder covering either (i) the unmodified
11+
** Software as contributed to or provided by such licensor, or (ii) the Larger
12+
** Works (as defined below), to deal in both
13+
**
14+
** (a) the Software, and
15+
** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16+
** one is included with the Software (each a "Larger Work" to which the Software
17+
** is contributed by such licensors),
18+
**
19+
** without restriction, including without limitation the rights to copy, create
20+
** derivative works of, display, perform, and distribute the Software and make,
21+
** use, sell, offer for sale, import, export, have made, and have sold the
22+
** Software and the Larger Work(s), and to sublicense the foregoing rights on
23+
** either these or other terms.
24+
**
25+
** This license is subject to the following condition:
26+
** The above copyright notice and either this complete permission notice or at
27+
** a minimum a reference to the UPL must be included in all copies or
28+
** substantial portions of the Software.
29+
**
30+
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
** SOFTWARE.
37+
*/
38+
39+
package tests
40+
41+
import (
42+
"fmt"
43+
"testing"
44+
)
45+
46+
type TestUser struct {
47+
ID uint `gorm:"primaryKey"`
48+
Username string `gorm:"uniqueIndex"`
49+
Email string
50+
Password string
51+
Role string
52+
}
53+
54+
var sqlInjectionTestCases = []string{
55+
"admin'; DROP TABLE \"test_users\"; --",
56+
"admin' UNION SELECT 1,\"username\",\"password\",1,1 FROM \"test_users\" --",
57+
"admin' AND 1=1 --",
58+
"admin' OR '1'='1' --",
59+
"admin' AND 1=2 --",
60+
"admin' OR '1'='2' --",
61+
"admin'; WAITFOR DELAY '00:00:05' --",
62+
"admin' AND (SELECT COUNT(*) FROM user_tables) > 0 --",
63+
"admin'; INSERT INTO \"test_users\" (\"username\",\"email\",\"role\") VALUES ('hacker','[email protected]','admin'); --",
64+
"admin' --",
65+
"admin\x00", // Null byte injection
66+
"0x61646D696E", // Hexadecimal representation of "admin"
67+
"admin%27%20OR%201%3D1%20--", // URL-encoded injection "admin' OR 1=1 --"
68+
}
69+
70+
func TestRawQueryInjection(t *testing.T) {
71+
if err := DB.AutoMigrate(&TestUser{}); err != nil {
72+
t.Errorf("failed to create test table: %v", err)
73+
}
74+
75+
testUsers := []TestUser{
76+
{Username: "admin", Email: "[email protected]", Password: "admin123", Role: "admin"},
77+
{Username: "user1", Email: "[email protected]", Password: "user123", Role: "user"},
78+
}
79+
for _, user := range testUsers {
80+
DB.FirstOrCreate(&user, TestUser{Username: user.Username})
81+
}
82+
for _, test := range sqlInjectionTestCases {
83+
var testUser []TestUser
84+
result := DB.Raw("SELECT * FROM \"test_users\" WHERE \"username\" = ?", test).Scan(&testUser)
85+
if result.Error == nil && len(testUser) > 0 {
86+
t.Errorf("Query should fail or returned no results: %v", result.Error)
87+
}
88+
89+
if !DB.Migrator().HasTable(&TestUser{}) {
90+
t.Errorf("Test table 'test_users' does not exist after migration")
91+
}
92+
93+
var count int64
94+
DB.Model(&TestUser{}).Where("\"username\" = ?", "hacker").Count(&count)
95+
if count > 0 {
96+
t.Errorf("Unexpected user 'hacker' was found!")
97+
}
98+
99+
var rowCount int64
100+
DB.Model(&TestUser{}).Count(&rowCount)
101+
if rowCount != 2 {
102+
t.Errorf("Expected user table to have 2 rows, but found %d", rowCount)
103+
}
104+
}
105+
DB.Migrator().DropTable(&TestUser{})
106+
}
107+
108+
func TestWhereClauseInjection(t *testing.T) {
109+
if err := DB.AutoMigrate(&TestUser{}); err != nil {
110+
t.Errorf("failed to create test table: %v", err)
111+
}
112+
113+
testUsers := []TestUser{
114+
{Username: "admin", Email: "[email protected]", Password: "admin123", Role: "admin"},
115+
{Username: "user1", Email: "[email protected]", Password: "user123", Role: "user"},
116+
}
117+
for _, user := range testUsers {
118+
DB.FirstOrCreate(&user, TestUser{Username: user.Username})
119+
}
120+
for _, test := range sqlInjectionTestCases {
121+
var testUser []TestUser
122+
result := DB.Where("\"username\" = ?", test).Find(&testUsers)
123+
if result.Error == nil && len(testUser) > 0 {
124+
t.Errorf("Query should fail or returned no results: %v", result.Error)
125+
}
126+
127+
if !DB.Migrator().HasTable(&TestUser{}) {
128+
t.Errorf("Test table 'test_users' does not exist after migration")
129+
}
130+
131+
var count int64
132+
DB.Model(&TestUser{}).Where("\"username\" = ?", "hacker").Count(&count)
133+
if count > 0 {
134+
t.Errorf("Unexpected user 'hacker' was found!")
135+
}
136+
137+
var rowCount int64
138+
DB.Model(&TestUser{}).Count(&rowCount)
139+
if rowCount != 2 {
140+
t.Errorf("Expected user table to have 2 rows, but found %d", rowCount)
141+
}
142+
}
143+
DB.Migrator().DropTable(&TestUser{})
144+
}
145+
146+
func TestUpdateInjection(t *testing.T) {
147+
if err := DB.AutoMigrate(&TestUser{}); err != nil {
148+
t.Errorf("failed to create test table: %v", err)
149+
}
150+
151+
testUser := TestUser{Username: "updatetest", Email: "[email protected]", Role: "user"}
152+
DB.Create(&testUser)
153+
154+
for _, test := range sqlInjectionTestCases {
155+
DB.Model(&testUser).Where("\"id\" = ?", testUser.ID).Update("email", test)
156+
var user TestUser
157+
result := DB.Where("username = ?", "updatetest").First(&user)
158+
if result.Error == nil && user.Email != test {
159+
t.Errorf("Expected email to be '%s', but got '%s'", test, user.Email)
160+
}
161+
162+
if !DB.Migrator().HasTable(&TestUser{}) {
163+
t.Errorf("Test table 'test_users' does not exist after migration")
164+
}
165+
166+
var count int64
167+
DB.Model(&TestUser{}).Where("\"username\" = ?", "hacker").Count(&count)
168+
if count > 0 {
169+
t.Errorf("Unexpected user 'hacker' was found!")
170+
}
171+
172+
var rowCount int64
173+
DB.Model(&TestUser{}).Count(&rowCount)
174+
if rowCount != 1 {
175+
t.Errorf("Expected user table to have 1 rows, but found %d", rowCount)
176+
}
177+
}
178+
DB.Migrator().DropTable(&TestUser{})
179+
}
180+
181+
func TestFirstOrCreateInjection(t *testing.T) {
182+
if err := DB.AutoMigrate(&TestUser{}); err != nil {
183+
t.Errorf("failed to create test table: %v", err)
184+
}
185+
186+
for i, test := range sqlInjectionTestCases {
187+
user := TestUser{
188+
Username: test,
189+
Email: fmt.Sprintf("test%[email protected]", i),
190+
Role: "user",
191+
}
192+
DB.FirstOrCreate(&user, TestUser{Username: test})
193+
194+
var count int64
195+
DB.Model(&TestUser{}).Where("\"username\" = ?", test).Count(&count)
196+
if count != 1 {
197+
t.Errorf("expected 1 record for input '%s', but found %d", test, count)
198+
}
199+
}
200+
201+
DB.Migrator().DropTable(&TestUser{})
202+
}

0 commit comments

Comments
 (0)