diff --git a/.envrc.example b/.envrc.example index 8cd541d16..0838af2fe 100644 --- a/.envrc.example +++ b/.envrc.example @@ -1,3 +1,5 @@ export BEARER_VERSION=latest export BEARER_WORKSPACE=$PWD/../bearer export GO_EXEC=go +export BEARER_DISABLE_VERSION_CHECK=true +export BEARER_DISABLE_DEFAULT_RULES=true diff --git a/rules/go/gosec/sql/concat_sqli.yml b/rules/go/gosec/sql/concat_sqli.yml index e6e809498..11ce2eabf 100644 --- a/rules/go/gosec/sql/concat_sqli.yml +++ b/rules/go/gosec/sql/concat_sqli.yml @@ -1,9 +1,16 @@ imports: - go_shared_lang_dynamic_request_input + - go_shared_lang_dynamic_input patterns: - pattern: | - $.Query($) + $.$($) filters: + - variable: METHOD + values: + - Query + - QueryRow + - Prepare + - Exec - variable: INPUT detection: go_gosec_sql_concat_sqli_unsanitized_input - not: @@ -19,11 +26,21 @@ patterns: - variable: DB detection: go_gosec_sql_concat_sqli_sql_db_begin scope: cursor + - variable: DB + regex: (?i).*(db|database) - pattern: | - $.QueryContext($<...>$) + $.$($<_>, $) filters: + - variable: METHOD + values: + - QueryContext + - PrepareContext + - ExecContext - variable: INPUT detection: go_gosec_sql_concat_sqli_unsanitized_input + - not: + variable: INPUT + detection: go_gosec_sql_concat_sqli_input_sprintf_sanitizer - either: - variable: DB detection: go_gosec_sql_concat_sqli_sql_open @@ -31,6 +48,8 @@ patterns: - variable: DB detection: go_gosec_sql_concat_sqli_sql_db_begin scope: cursor + - variable: DB + string_regex: (?i).*(db|database) auxiliary: - id: go_gosec_sql_concat_sqli_input_sprintf_sanitizer patterns: @@ -46,6 +65,9 @@ auxiliary: patterns: - pattern: $ filters: + - variable: INPUT + detection: go_shared_lang_dynamic_input + scope: cursor - variable: INPUT detection: go_shared_lang_dynamic_request_input scope: cursor diff --git a/rules/go/shared/lang/dynamic_input.yml b/rules/go/shared/lang/dynamic_input.yml index 333d7ae73..b46e679eb 100644 --- a/rules/go/shared/lang/dynamic_input.yml +++ b/rules/go/shared/lang/dynamic_input.yml @@ -26,6 +26,7 @@ auxiliary: - os.Args - os.Getenv() - func $<_>($<...>$$ $<_>$<...>) + - func ($<...>) $<_>($<...>$$<_> $<_>$<...>)$<...> metadata: description: "Go dynamic input." id: go_shared_lang_dynamic_input diff --git a/tests/go/gosec/sql/concat_sqli/test.js b/tests/go/gosec/sql/concat_sqli/test.js index feb638403..b28b4f3cf 100644 --- a/tests/go/gosec/sql/concat_sqli/test.js +++ b/tests/go/gosec/sql/concat_sqli/test.js @@ -1,4 +1,8 @@ -const { createInvoker, getEnvironment } = require("../../../../helper.js") +const { + createInvoker, + createNewInvoker, + getEnvironment, +} = require("../../../../helper.js") const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) describe(ruleId, () => { @@ -14,3 +18,236 @@ describe(ruleId, () => { expect(invoke(testCase)).toMatchSnapshot() }) }) + +describe(`${ruleId}-xx`, () => { + const invoke = createNewInvoker(ruleId, ruleFile, testBase) + + test("test", () => { + const testCase = "function.go" + + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test1", () => { + const testCase = "test01.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test2", () => { + const testCase = "test02.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test3", () => { + const testCase = "test03.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test4", () => { + const testCase = "test04.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test5", () => { + const testCase = "test05.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test6", () => { + const testCase = "test06.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test7", () => { + const testCase = "test07.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test8", () => { + const testCase = "test08.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test9", () => { + const testCase = "test09.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test10", () => { + const testCase = "test10.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test11", () => { + const testCase = "test11.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test12", () => { + const testCase = "test12.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test13", () => { + const testCase = "test13.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test14", () => { + const testCase = "test14.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test15", () => { + const testCase = "test15.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) +}) + +describe(`${ruleId}-1xx`, () => { + const invoke = createNewInvoker(ruleId, ruleFile, testBase) + + test("test101", () => { + const testCase = "test101.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test102", () => { + const testCase = "test102.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test103", () => { + const testCase = "test103.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test104", () => { + const testCase = "test104.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test105", () => { + const testCase = "test105.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test106", () => { + const testCase = "test106.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test107", () => { + const testCase = "test107.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test108", () => { + const testCase = "test108.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test109", () => { + const testCase = "test109.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test110", () => { + const testCase = "test110.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test111", () => { + const testCase = "test111.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) + + test("test112", () => { + const testCase = "test112.go" + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) +}) diff --git a/tests/go/gosec/sql/concat_sqli/testdata/function.go b/tests/go/gosec/sql/concat_sqli/testdata/function.go new file mode 100644 index 000000000..b7af39305 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/function.go @@ -0,0 +1,73 @@ +package sqli + +import ( + "database/sql" + "fmt" + "log" + + "github.com/foo/utils/database" +) + +var DB *sql.DB +var err error + +type Profile struct { + Uid int + Name string + City string + PhoneNumber string +} + +func NewProfile() *Profile { + return &Profile{} +} + +func (p *Profile) UnsafeQueryGetData(uid string) error { + + /* this funciton use to get data Profile from database with vulnerable query */ + DB, err = database.Connect() + + getProfileSql := fmt.Sprintf(`SELECT p.user_id, p.full_name, p.city, p.phone_number + FROM Profile as p,Users as u + where p.user_id = u.id + and u.id=%s`, uid) //here is the vulnerable query + + // bearer:expected go_gosec_sql_concat_sqli + rows, err := DB.Query(getProfileSql) + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + err = rows.Scan(&p.Uid, &p.Name, &p.City, &p.PhoneNumber) + if err != nil { + log.Printf("Row scan error: %s", err.Error()) + return err + } + } + return nil +} + +func (p *Profile) SafeQueryGetData(uid string) error { + DB, err = database.Connect() + + const ( + getProfileSql = `SELECT p.user_id, p.full_name, p.city, p.phone_number + FROM Profile as p,Users as u + where p.user_id = u.id + and u.id=?` + ) + + stmt, err := DB.Prepare(getProfileSql) //prepare statement + if err != nil { + return err + } + + defer stmt.Close() + err = stmt.QueryRow(uid).Scan(&p.Uid, &p.Name, &p.City, &p.PhoneNumber) + if err != nil { + return err + } + return nil +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test01.go b/tests/go/gosec/sql/concat_sqli/testdata/test01.go new file mode 100644 index 000000000..edb6a2976 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test01.go @@ -0,0 +1,22 @@ +// Format string without proper quoting +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT * FROM foo where name = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test02.go b/tests/go/gosec/sql/concat_sqli/testdata/test02.go new file mode 100644 index 000000000..8502936b2 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test02.go @@ -0,0 +1,22 @@ +// Format string without proper quoting case insensitive +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("select * from foo where name = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test03.go b/tests/go/gosec/sql/concat_sqli/testdata/test03.go new file mode 100644 index 000000000..79675a4eb --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test03.go @@ -0,0 +1,23 @@ +// Format string without proper quoting with context +package main + +import ( + "context" + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("select * from foo where name = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.QueryContext(context.Background(), q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test04.go b/tests/go/gosec/sql/concat_sqli/testdata/test04.go new file mode 100644 index 000000000..427350d5a --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test04.go @@ -0,0 +1,31 @@ +// Format string without proper quoting with transaction +package main + +import ( + "context" + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + tx, err := db.Begin() + if err != nil { + panic(err) + } + defer tx.Rollback() + q := fmt.Sprintf("select * from foo where name = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + rows, err := tx.QueryContext(context.Background(), q) + if err != nil { + panic(err) + } + defer rows.Close() + if err := tx.Commit(); err != nil { + panic(err) + } +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test05.go b/tests/go/gosec/sql/concat_sqli/testdata/test05.go new file mode 100644 index 000000000..7f31cef87 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test05.go @@ -0,0 +1,21 @@ +// Format string false positive, safe string spec. +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT * FROM foo where id = %d", os.Args[1]) + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test06.go b/tests/go/gosec/sql/concat_sqli/testdata/test06.go new file mode 100644 index 000000000..186218692 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test06.go @@ -0,0 +1,20 @@ +// Format string false positive +package main + +import ( + "database/sql" +) + +const staticQuery = "SELECT * FROM foo WHERE age < 32" + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + rows, err := db.Query(staticQuery) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test07.go b/tests/go/gosec/sql/concat_sqli/testdata/test07.go new file mode 100644 index 000000000..42c9b0c08 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test07.go @@ -0,0 +1,23 @@ +// Format string false positive, quoted formatter argument. +package main + +import ( + "database/sql" + "fmt" + "os" + + "github.com/lib/pq" +) + +func main() { + db, err := sql.Open("postgres", "localhost") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT * FROM %s where id = 1", pq.QuoteIdentifier(os.Args[1])) + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test08.go b/tests/go/gosec/sql/concat_sqli/testdata/test08.go new file mode 100644 index 000000000..ccad21c80 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test08.go @@ -0,0 +1,22 @@ +// false positive +package main + +import ( + "database/sql" + "fmt" +) + +const Table = "foo" + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT * FROM %s where id = 1", Table) + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test09.go b/tests/go/gosec/sql/concat_sqli/testdata/test09.go new file mode 100644 index 000000000..0a2ef9d4a --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test09.go @@ -0,0 +1,22 @@ +// Format string with \n\r +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT * FROM foo where\n name = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test10.go b/tests/go/gosec/sql/concat_sqli/testdata/test10.go new file mode 100644 index 000000000..1168bb2ab --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test10.go @@ -0,0 +1,22 @@ +// Format string with \n\r +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT * FROM foo where\nname = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test101.go b/tests/go/gosec/sql/concat_sqli/testdata/test101.go new file mode 100644 index 000000000..2e8a544da --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test101.go @@ -0,0 +1,22 @@ +// infixed concatenation +package main + +import ( + "database/sql" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + + q := "INSERT INTO foo (name) VALUES ('" + os.Args[0] + "')" + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query(q) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test102.go b/tests/go/gosec/sql/concat_sqli/testdata/test102.go new file mode 100644 index 000000000..3f1dbfeb8 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test102.go @@ -0,0 +1,19 @@ +package main + +import ( + "database/sql" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query("SELECT * FROM foo WHERE name = " + os.Args[1]) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test103.go b/tests/go/gosec/sql/concat_sqli/testdata/test103.go new file mode 100644 index 000000000..c1847e3a2 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test103.go @@ -0,0 +1,20 @@ +// case insensitive match +package main + +import ( + "database/sql" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query("select * from foo where name = " + os.Args[1]) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test104.go b/tests/go/gosec/sql/concat_sqli/testdata/test104.go new file mode 100644 index 000000000..bb19f17bb --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test104.go @@ -0,0 +1,21 @@ +// context match +package main + +import ( + "context" + "database/sql" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.QueryContext(context.Background(), "select * from foo where name = "+os.Args[1]) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test105.go b/tests/go/gosec/sql/concat_sqli/testdata/test105.go new file mode 100644 index 000000000..10f5db23f --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test105.go @@ -0,0 +1,29 @@ +// DB transaction check +package main + +import ( + "context" + "database/sql" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + tx, err := db.Begin() + if err != nil { + panic(err) + } + defer tx.Rollback() + // bearer:expected go_gosec_sql_concat_sqli + rows, err := tx.QueryContext(context.Background(), "select * from foo where name = "+os.Args[1]) + if err != nil { + panic(err) + } + defer rows.Close() + if err := tx.Commit(); err != nil { + panic(err) + } +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test106.go b/tests/go/gosec/sql/concat_sqli/testdata/test106.go new file mode 100644 index 000000000..fd47cbb01 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test106.go @@ -0,0 +1,20 @@ +// multiple string concatenation +package main + +import ( + "database/sql" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + // bearer:expected go_gosec_sql_concat_sqli + rows, err := db.Query("SELECT * FROM foo" + "WHERE name = " + os.Args[1]) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test107.go b/tests/go/gosec/sql/concat_sqli/testdata/test107.go new file mode 100644 index 000000000..ce6e3ee4e --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test107.go @@ -0,0 +1,20 @@ +// false positive +package main + +import ( + "database/sql" +) + +var staticQuery = "SELECT * FROM foo WHERE age < " + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + rows, err := db.Query(staticQuery + "32") + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test108.go b/tests/go/gosec/sql/concat_sqli/testdata/test108.go new file mode 100644 index 000000000..6c131b1e8 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test108.go @@ -0,0 +1,21 @@ +package main + +import ( + "database/sql" +) + +const age = "32" + +var staticQuery = "SELECT * FROM foo WHERE age < " + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + rows, err := db.Query(staticQuery + age) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test109.go b/tests/go/gosec/sql/concat_sqli/testdata/test109.go new file mode 100644 index 000000000..326216548 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test109.go @@ -0,0 +1,21 @@ +package main + +import ( + "database/sql" +) + +const age = "32" + +var staticQuery = "SELECT * FROM foo WHERE age < " + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + rows, err := db.Query("SELECT * FROM foo WHERE gender = " + gender) + if err != nil { + panic(err) + } + defer rows.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test11.go b/tests/go/gosec/sql/concat_sqli/testdata/test11.go new file mode 100644 index 000000000..a51c26a11 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test11.go @@ -0,0 +1,24 @@ +// SQLI by db.Query(some).Scan(&other) +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + var name string + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT name FROM users where id = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + row := db.QueryRow(q) + err = row.Scan(&name) + if err != nil { + panic(err) + } + defer db.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test110.go b/tests/go/gosec/sql/concat_sqli/testdata/test110.go new file mode 100644 index 000000000..c41ae875f --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test110.go @@ -0,0 +1,22 @@ +// ExecContext match +package main + +import ( + "context" + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + // bearer:expected go_gosec_sql_concat_sqli + result, err := db.ExecContext(context.Background(), "select * from foo where name = "+os.Args[1]) + if err != nil { + panic(err) + } + fmt.Println(result) +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test111.go b/tests/go/gosec/sql/concat_sqli/testdata/test111.go new file mode 100644 index 000000000..7f4ec96a6 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test111.go @@ -0,0 +1,21 @@ +// Exec match +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + // bearer:expected go_gosec_sql_concat_sqli + result, err := db.Exec("select * from foo where name = " + os.Args[1]) + if err != nil { + panic(err) + } + fmt.Println(result) +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test112.go b/tests/go/gosec/sql/concat_sqli/testdata/test112.go new file mode 100644 index 000000000..b99a9293e --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test112.go @@ -0,0 +1,23 @@ +package main + +import ( + "database/sql" + "fmt" +) + +const gender = "M" +const age = "32" + +var staticQuery = "SELECT * FROM foo WHERE age < " + +func main() { + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + result, err := db.Exec("SELECT * FROM foo WHERE gender = " + gender) + if err != nil { + panic(err) + } + fmt.Println(result) +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test12.go b/tests/go/gosec/sql/concat_sqli/testdata/test12.go new file mode 100644 index 000000000..5053ccee4 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test12.go @@ -0,0 +1,23 @@ +// SQLI by db.Query(some).Scan(&other) +package main + +import ( + "database/sql" + "fmt" + "os" +) + +func main() { + var name string + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT name FROM users where id = '%s'", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + err = db.QueryRow(q).Scan(&name) + if err != nil { + panic(err) + } + defer db.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test13.go b/tests/go/gosec/sql/concat_sqli/testdata/test13.go new file mode 100644 index 000000000..27a921d1a --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test13.go @@ -0,0 +1,32 @@ +// SQLI by db.Prepare(some) +package main + +import ( + "database/sql" + "fmt" + "log" + "os" +) + +const Table = "foo" + +func main() { + var album string + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT name FROM users where '%s' = ?", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + stmt, err := db.Prepare(q) + if err != nil { + log.Fatal(err) + } + stmt.QueryRow(fmt.Sprintf("%s", os.Args[2])).Scan(&album) + if err != nil { + if err == sql.ErrNoRows { + log.Fatal(err) + } + } + defer stmt.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test14.go b/tests/go/gosec/sql/concat_sqli/testdata/test14.go new file mode 100644 index 000000000..07cbf4ce9 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test14.go @@ -0,0 +1,33 @@ +// SQLI by db.PrepareContext(some) +package main + +import ( + "context" + "database/sql" + "fmt" + "log" + "os" +) + +const Table = "foo" + +func main() { + var album string + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + q := fmt.Sprintf("SELECT name FROM users where '%s' = ?", os.Args[1]) + // bearer:expected go_gosec_sql_concat_sqli + stmt, err := db.PrepareContext(context.Background(), q) + if err != nil { + log.Fatal(err) + } + stmt.QueryRow(fmt.Sprintf("%s", os.Args[2])).Scan(&album) + if err != nil { + if err == sql.ErrNoRows { + log.Fatal(err) + } + } + defer stmt.Close() +} diff --git a/tests/go/gosec/sql/concat_sqli/testdata/test15.go b/tests/go/gosec/sql/concat_sqli/testdata/test15.go new file mode 100644 index 000000000..2cbeba890 --- /dev/null +++ b/tests/go/gosec/sql/concat_sqli/testdata/test15.go @@ -0,0 +1,30 @@ +// false positive +package main + +import ( + "database/sql" + "fmt" + "log" + "os" +) + +const Table = "foo" + +func main() { + var album string + db, err := sql.Open("sqlite3", ":memory:") + if err != nil { + panic(err) + } + stmt, err := db.Prepare("SELECT * FROM album WHERE id = ?") + if err != nil { + log.Fatal(err) + } + stmt.QueryRow(fmt.Sprintf("%s", os.Args[1])).Scan(&album) + if err != nil { + if err == sql.ErrNoRows { + log.Fatal(err) + } + } + defer stmt.Close() +} diff --git a/tests/helper.js b/tests/helper.js index 3e9ae2d00..baa90ba2c 100644 --- a/tests/helper.js +++ b/tests/helper.js @@ -93,14 +93,19 @@ FORMAT=jsonv2 bearer scan ${testBase} --only-rule ${ruleId} --log-level trace` } results = JSON.parse(out) + let findings = [] - for (const result of results.findings) { - findings.push(`${result.id}:${result.source.start}`) + if (results.findings != null) { + for (const result of results.findings) { + findings.push(`${result.id}:${result.source.start}`) + } } let expectedFindings = [] - for (const result of results.expected_findings) { - expectedFindings.push(`${result.rule_id}:${result.location.start}`) + if (results.expected_findings != null) { + for (const result of results.expected_findings) { + expectedFindings.push(`${result.rule_id}:${result.location.start}`) + } } return {