gosec/testutils/source.go

4045 lines
67 KiB
Go
Raw Permalink Normal View History

package testutils
import "github.com/securego/gosec/v2"
// CodeSample encapsulates a snippet of source code that compiles, and how many errors should be detected
type CodeSample struct {
Code []string
Errors int
Config gosec.Config
}
var (
// SampleCodeG101 code snippets for hardcoded credentials
SampleCodeG101 = []CodeSample{
{[]string{`
package main
import "fmt"
func main() {
username := "admin"
password := "f62e5bcda4fae4f82370da0c6f20697b8f8447ef"
fmt.Println("Doing something with: ", username, password)
}`}, 1, gosec.NewConfig()},
{[]string{`
// Entropy check should not report this error by default
package main
import "fmt"
func main() {
username := "admin"
password := "secret"
fmt.Println("Doing something with: ", username, password)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
var password = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef"
func main() {
username := "admin"
fmt.Println("Doing something with: ", username, password)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
const password = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef"
func main() {
username := "admin"
fmt.Println("Doing something with: ", username, password)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
const (
username = "user"
password = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef"
)
func main() {
fmt.Println("Doing something with: ", username, password)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
var password string
func init() {
password = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef"
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
const (
ATNStateSomethingElse = 1
ATNStateTokenStart = 42
)
func main() {
println(ATNStateTokenStart)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
const (
ATNStateTokenStart = "f62e5bcda4fae4f82370da0c6f20697b8f8447ef"
)
func main() {
println(ATNStateTokenStart)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
var password string
if password == "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" {
fmt.Println("password equality")
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
var password string
if "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" == password {
fmt.Println("password equality")
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
var password string
if password != "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" {
fmt.Println("password equality")
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
var password string
if "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" != password {
fmt.Println("password equality")
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
var p string
if p != "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" {
fmt.Println("password equality")
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
var p string
if "f62e5bcda4fae4f82370da0c6f20697b8f8447ef" != p {
fmt.Println("password equality")
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
const (
pw = "KjasdlkjapoIKLlka98098sdf012U/rL2sLdBqOHQUlt5Z6kCgKGDyCFA=="
)
func main() {
fmt.Println(pw)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
var (
pw string
)
func main() {
pw = "KjasdlkjapoIKLlka98098sdf012U/rL2sLdBqOHQUlt5Z6kCgKGDyCFA=="
fmt.Println(pw)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
const (
cred = "KjasdlkjapoIKLlka98098sdf012U/rL2sLdBqOHQUlt5Z6kCgKGDyCFA=="
)
func main() {
fmt.Println(cred)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
var (
cred string
)
func main() {
cred = "KjasdlkjapoIKLlka98098sdf012U/rL2sLdBqOHQUlt5Z6kCgKGDyCFA=="
fmt.Println(cred)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
const (
apiKey = "KjasdlkjapoIKLlka98098sdf012U"
)
func main() {
fmt.Println(apiKey)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
var (
apiKey string
)
func main() {
apiKey = "KjasdlkjapoIKLlka98098sdf012U"
fmt.Println(apiKey)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
const (
bearer = "Bearer: 2lkjdfoiuwer092834kjdwf09"
)
func main() {
fmt.Println(bearer)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
var (
bearer string
)
func main() {
bearer = "Bearer: 2lkjdfoiuwer092834kjdwf09"
fmt.Println(bearer)
}`}, 1, gosec.NewConfig()},
}
// SampleCodeG101Values code snippets for hardcoded credentials
SampleCodeG101Values = []CodeSample{
{[]string{`
package main
import "fmt"
func main() {
customerNameEnvKey := "FOO_CUSTOMER_NAME"
fmt.Println(customerNameEnvKey)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
txnID := "3637cfcc1eec55a50f78a7c435914583ccbc75a21dec9a0e94dfa077647146d7"
fmt.Println(txnID)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
urlSecret := "https://username:abcdef0123456789abcdef0123456789abcdef01@contoso.com/"
fmt.Println(urlSecret)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
githubToken := "ghp_iR54dhCYg9Tfmoywi9xLmmKZrrnAw438BYh3"
fmt.Println(githubToken)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
awsAccessKeyID := "AKIAI44QH8DHBEXAMPLE"
fmt.Println(awsAccessKeyID)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
compareGoogleAPI := "test"
if compareGoogleAPI == "AIzajtGS_aJGkoiAmSbXzu9I-1eytAi9Lrlh-vT" {
fmt.Println(compareGoogleAPI)
}
}`}, 1, gosec.NewConfig()},
}
// SampleCodeG102 code snippets for network binding
SampleCodeG102 = []CodeSample{
// Bind to all networks explicitly
{[]string{`
package main
import (
"log"
"net"
)
func main() {
l, err := net.Listen("tcp", "0.0.0.0:2000")
if err != nil {
log.Fatal(err)
}
defer l.Close()
}`}, 1, gosec.NewConfig()},
// Bind to all networks implicitly (default if host omitted)
{[]string{`
package main
import (
"log"
"net"
)
func main() {
l, err := net.Listen("tcp", ":2000")
if err != nil {
log.Fatal(err)
}
defer l.Close()
}`}, 1, gosec.NewConfig()},
// Bind to all networks indirectly through a parsing function
{[]string{`
package main
import (
"log"
"net"
)
func parseListenAddr(listenAddr string) (network string, addr string) {
return "", ""
}
func main() {
addr := ":2000"
l, err := net.Listen(parseListenAddr(addr))
if err != nil {
log.Fatal(err)
}
defer l.Close()
}`}, 1, gosec.NewConfig()},
// Bind to all networks indirectly through a parsing function
{[]string{`
package main
import (
"log"
"net"
)
const addr = ":2000"
func parseListenAddr(listenAddr string) (network string, addr string) {
return "", ""
}
func main() {
l, err := net.Listen(parseListenAddr(addr))
if err != nil {
log.Fatal(err)
}
defer l.Close()
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"log"
"net"
)
const addr = "0.0.0.0:2000"
func main() {
l, err := net.Listen("tcp", addr)
if err != nil {
log.Fatal(err)
}
defer l.Close()
}`}, 1, gosec.NewConfig()},
}
// SampleCodeG103 find instances of unsafe blocks for auditing purposes
SampleCodeG103 = []CodeSample{
{[]string{`
package main
import (
"fmt"
"unsafe"
)
type Fake struct{}
func (Fake) Good() {}
func main() {
unsafeM := Fake{}
unsafeM.Good()
intArray := [...]int{1, 2}
fmt.Printf("\nintArray: %v\n", intArray)
intPtr := &intArray[0]
fmt.Printf("\nintPtr=%p, *intPtr=%d.\n", intPtr, *intPtr)
addressHolder := uintptr(unsafe.Pointer(intPtr))
intPtr = (*int)(unsafe.Pointer(addressHolder))
fmt.Printf("\nintPtr=%p, *intPtr=%d.\n\n", intPtr, *intPtr)
}`}, 2, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"unsafe"
)
func main() {
chars := [...]byte{1, 2}
charsPtr := &chars[0]
str := unsafe.String(charsPtr, len(chars))
fmt.Printf("%s\n", str)
ptr := unsafe.StringData(str)
fmt.Printf("ptr: %p\n", ptr)
}`}, 2, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"unsafe"
)
func main() {
chars := [...]byte{1, 2}
charsPtr := &chars[0]
slice := unsafe.Slice(charsPtr, len(chars))
fmt.Printf("%v\n", slice)
ptr := unsafe.SliceData(slice)
fmt.Printf("ptr: %p\n", ptr)
}`}, 2, gosec.NewConfig()},
}
// SampleCodeG104 finds errors that aren't being handled
SampleCodeG104 = []CodeSample{
{[]string{`
package main
import "fmt"
func test() (int,error) {
return 0, nil
}
func main() {
v, _ := test()
fmt.Println(v)
}`}, 0, gosec.NewConfig()}, {[]string{`
package main
import (
"io/ioutil"
"os"
"fmt"
)
func a() error {
return fmt.Errorf("This is an error")
}
func b() {
fmt.Println("b")
ioutil.WriteFile("foo.txt", []byte("bar"), os.ModeExclusive)
}
func c() string {
return fmt.Sprintf("This isn't anything")
}
func main() {
_ = a()
a()
b()
c()
}`}, 2, gosec.NewConfig()}, {[]string{`
package main
import "fmt"
func test() error {
return nil
}
func main() {
e := test()
fmt.Println(e)
}`}, 0, gosec.NewConfig()}, {[]string{`
// +build go1.10
package main
import "strings"
func main() {
var buf strings.Builder
_, err := buf.WriteString("test string")
if err != nil {
panic(err)
}
}`, `
package main
func dummy(){}
`}, 0, gosec.NewConfig()}, {[]string{`
package main
import (
"bytes"
)
type a struct {
buf *bytes.Buffer
}
func main() {
a := &a{
buf: new(bytes.Buffer),
}
a.buf.Write([]byte{0})
}
`}, 0, gosec.NewConfig()}, {[]string{`
package main
import (
"io/ioutil"
"os"
"fmt"
)
func a() {
fmt.Println("a")
ioutil.WriteFile("foo.txt", []byte("bar"), os.ModeExclusive)
}
func main() {
a()
}`}, 0, gosec.Config{"G104": map[string]interface{}{"ioutil": []interface{}{"WriteFile"}}}}, {[]string{`
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
)
func createBuffer() *bytes.Buffer {
return new(bytes.Buffer)
}
func main() {
new(bytes.Buffer).WriteString("*bytes.Buffer")
fmt.Fprintln(os.Stderr, "fmt")
new(strings.Builder).WriteString("*strings.Builder")
_, pw := io.Pipe()
pw.CloseWithError(io.EOF)
createBuffer().WriteString("*bytes.Buffer")
b := createBuffer()
b.WriteString("*bytes.Buffer")
}`}, 0, gosec.NewConfig()},
2023-05-26 16:03:54 +01:00
} // it shouldn't return any errors because all method calls are whitelisted by default
// SampleCodeG104Audit finds errors that aren't being handled in audit mode
SampleCodeG104Audit = []CodeSample{
{[]string{`
package main
import "fmt"
func test() (int,error) {
return 0, nil
}
func main() {
v, _ := test()
fmt.Println(v)
}`}, 1, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}}, {[]string{`
package main
import (
"io/ioutil"
"os"
"fmt"
)
func a() error {
return fmt.Errorf("This is an error")
}
func b() {
fmt.Println("b")
ioutil.WriteFile("foo.txt", []byte("bar"), os.ModeExclusive)
}
func c() string {
return fmt.Sprintf("This isn't anything")
}
func main() {
_ = a()
a()
b()
c()
}`}, 3, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}}, {[]string{`
package main
import "fmt"
func test() error {
return nil
}
func main() {
e := test()
fmt.Println(e)
}`}, 0, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}}, {[]string{`
// +build go1.10
package main
import "strings"
func main() {
var buf strings.Builder
_, err := buf.WriteString("test string")
if err != nil {
panic(err)
}
}`, `
package main
func dummy(){}
`}, 0, gosec.Config{gosec.Globals: map[gosec.GlobalOption]string{gosec.Audit: "enabled"}}},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG106 - ssh InsecureIgnoreHostKey
SampleCodeG106 = []CodeSample{{[]string{`
package main
import (
"golang.org/x/crypto/ssh"
)
func main() {
2018-02-07 08:23:52 +00:00
_ = ssh.InsecureIgnoreHostKey()
}`}, 1, gosec.NewConfig()}}
// SampleCodeG107 - SSRF via http requests with variable url
SampleCodeG107 = []CodeSample{{[]string{`
// Input from the std in is considered insecure
package main
import (
"net/http"
"io/ioutil"
"fmt"
"os"
"bufio"
)
func main() {
in := bufio.NewReader(os.Stdin)
url, err := in.ReadString('\n')
if err != nil {
panic(err)
}
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Printf("%s", body)
}`}, 1, gosec.NewConfig()}, {[]string{`
// Variable defined a package level can be changed at any time
// regardless of the initial value
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
var url string = "https://www.google.com"
func main() {
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Printf("%s", body)
}`}, 1, gosec.NewConfig()}, {[]string{`
// Environmental variables are not considered as secure source
package main
import (
"net/http"
"io/ioutil"
"fmt"
"os"
)
func main() {
url := os.Getenv("tainted_url")
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Printf("%s", body)
}`}, 1, gosec.NewConfig()}, {[]string{`
// Constant variables or hard-coded strings are secure
package main
import (
"fmt"
"net/http"
)
const url = "http://127.0.0.1"
func main() {
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
fmt.Println(resp.Status)
}`}, 0, gosec.NewConfig()}, {[]string{`
// A variable at function scope which is initialized to
// a constant string is secure (e.g. cannot be changed concurrently)
package main
import (
"fmt"
"net/http"
)
func main() {
var url string = "http://127.0.0.1"
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
fmt.Println(resp.Status)
}`}, 0, gosec.NewConfig()}, {[]string{`
// A variable at function scope which is initialized to
// a constant string is secure (e.g. cannot be changed concurrently)
package main
import (
"fmt"
"net/http"
)
func main() {
url := "http://127.0.0.1"
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
fmt.Println(resp.Status)
}`}, 0, gosec.NewConfig()}, {[]string{`
// A variable at function scope which is initialized to
// a constant string is secure (e.g. cannot be changed concurrently)
package main
import (
"fmt"
"net/http"
)
func main() {
url1 := "test"
var url2 string = "http://127.0.0.1"
url2 = url1
resp, err := http.Get(url2)
if err != nil {
fmt.Println(err)
}
fmt.Println(resp.Status)
}`}, 0, gosec.NewConfig()}, {[]string{`
// An exported variable declared a packaged scope is not secure
// because it can changed at any time
package main
import (
"fmt"
"net/http"
)
var Url string
func main() {
resp, err := http.Get(Url)
if err != nil {
fmt.Println(err)
}
fmt.Println(resp.Status)
}`}, 1, gosec.NewConfig()}, {[]string{`
// An url provided as a function argument is not secure
package main
import (
"fmt"
"net/http"
)
func get(url string) {
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
fmt.Println(resp.Status)
}
func main() {
url := "http://127.0.0.1"
get(url)
}`}, 1, gosec.NewConfig()}}
// SampleCodeG108 - pprof endpoint automatically exposed
SampleCodeG108 = []CodeSample{{[]string{`
package main
import (
"fmt"
"log"
"net/http"
_ "net/http/pprof"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}`}, 0, gosec.NewConfig()}}
// SampleCodeG109 - Potential Integer OverFlow
SampleCodeG109 = []CodeSample{
{[]string{`
package main
import (
"fmt"
"strconv"
)
func main() {
bigValue, err := strconv.Atoi("2147483648")
if err != nil {
panic(err)
}
value := int32(bigValue)
fmt.Println(value)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"strconv"
)
func main() {
bigValue, err := strconv.Atoi("32768")
if err != nil {
panic(err)
}
if int16(bigValue) < 0 {
fmt.Println(bigValue)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"strconv"
)
func main() {
bigValue, err := strconv.Atoi("2147483648")
if err != nil {
panic(err)
}
fmt.Println(bigValue)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"strconv"
)
func main() {
bigValue, err := strconv.Atoi("2147483648")
if err != nil {
panic(err)
}
fmt.Println(bigValue)
test()
}
func test() {
bigValue := 30
value := int32(bigValue)
fmt.Println(value)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"strconv"
)
func main() {
value := 10
if value == 10 {
value, _ := strconv.Atoi("2147483648")
fmt.Println(value)
}
v := int32(value)
fmt.Println(v)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"strconv"
)
func main() {
a, err := strconv.Atoi("a")
b := int32(a) //#nosec G109
fmt.Println(b, err)
}`}, 0, gosec.NewConfig()},
}
// SampleCodeG110 - potential DoS vulnerability via decompression bomb
SampleCodeG110 = []CodeSample{
{[]string{`
package main
import (
"bytes"
"compress/zlib"
"io"
"os"
)
func main() {
buff := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207,
47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147}
b := bytes.NewReader(buff)
r, err := zlib.NewReader(b)
if err != nil {
panic(err)
}
2021-01-01 19:45:13 +00:00
_, err = io.Copy(os.Stdout, r)
if err != nil {
panic(err)
}
r.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"bytes"
"compress/zlib"
"io"
"os"
)
func main() {
buff := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207,
47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147}
b := bytes.NewReader(buff)
r, err := zlib.NewReader(b)
if err != nil {
panic(err)
}
buf := make([]byte, 8)
2021-01-01 19:45:13 +00:00
_, err = io.CopyBuffer(os.Stdout, r, buf)
if err != nil {
panic(err)
}
r.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"archive/zip"
"io"
"os"
"strconv"
)
func main() {
r, err := zip.OpenReader("tmp.zip")
if err != nil {
panic(err)
}
defer r.Close()
for i, f := range r.File {
out, err := os.OpenFile("output" + strconv.Itoa(i), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
panic(err)
}
rc, err := f.Open()
if err != nil {
panic(err)
}
_, err = io.Copy(out, rc)
out.Close()
rc.Close()
if err != nil {
panic(err)
}
}
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"io"
"os"
)
func main() {
s, err := os.Open("src")
if err != nil {
panic(err)
}
defer s.Close()
d, err := os.Create("dst")
if err != nil {
panic(err)
}
defer d.Close()
_, err = io.Copy(d, s)
if err != nil {
panic(err)
}
}`}, 0, gosec.NewConfig()},
}
// SampleCodeG111 - potential directory traversal
SampleCodeG111 = []CodeSample{
{[]string{`
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.Handle("/bad/", http.StripPrefix("/bad/", http.FileServer(http.Dir("/"))))
http.HandleFunc("/", HelloServer)
log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), nil))
}
func HelloServer(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}`}, 1, gosec.NewConfig()},
}
2022-04-30 11:38:50 +01:00
// SampleCodeG112 - potential slowloris attack
SampleCodeG112 = []CodeSample{
{[]string{`
package main
import (
"fmt"
"net/http"
)
2022-04-30 11:38:50 +01:00
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
})
err := (&http.Server{
Addr: ":1234",
}).ListenAndServe()
if err != nil {
panic(err)
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"time"
"net/http"
)
2022-04-30 11:38:50 +01:00
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
})
server := &http.Server{
Addr: ":1234",
ReadHeaderTimeout: 3 * time.Second,
}
err := server.ListenAndServe()
if err != nil {
panic(err)
}
}
`}, 0, gosec.NewConfig()},
2022-06-23 13:58:13 +01:00
{[]string{`
package main
import (
"fmt"
"time"
"net/http"
)
2022-06-23 13:58:13 +01:00
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
})
server := &http.Server{
Addr: ":1234",
ReadTimeout: 1 * time.Second,
}
err := server.ListenAndServe()
if err != nil {
panic(err)
}
}
`}, 0, gosec.NewConfig()},
2022-04-30 11:38:50 +01:00
}
// SampleCodeG113 - Usage of Rat.SetString in math/big with an overflow
SampleCodeG113 = []CodeSample{
{[]string{
`
package main
import (
"math/big"
"fmt"
)
func main() {
r := big.Rat{}
r.SetString("13e-9223372036854775808")
fmt.Println(r)
}`,
}, 1, gosec.NewConfig()},
}
// SampleCodeG114 - Use of net/http serve functions that have no support for setting timeouts
SampleCodeG114 = []CodeSample{
{[]string{
`
package main
import (
"log"
"net/http"
)
func main() {
err := http.ListenAndServe(":8080", nil)
log.Fatal(err)
}`,
}, 1, gosec.NewConfig()},
{
[]string{
`
package main
import (
"log"
"net/http"
)
func main() {
err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", nil)
log.Fatal(err)
}`,
}, 1, gosec.NewConfig(),
},
{
[]string{
`
package main
import (
"log"
"net"
"net/http"
)
func main() {
l, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
defer l.Close()
err = http.Serve(l, nil)
log.Fatal(err)
}`,
}, 1, gosec.NewConfig(),
},
{
[]string{
`
package main
import (
"log"
"net"
"net/http"
)
func main() {
l, err := net.Listen("tcp", ":8443")
if err != nil {
log.Fatal(err)
}
defer l.Close()
err = http.ServeTLS(l, nil, "cert.pem", "key.pem")
log.Fatal(err)
}`,
}, 1, gosec.NewConfig(),
},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG201 - SQL injection via format string
SampleCodeG201 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
// Format string without proper quoting
package main
2017-12-28 06:54:10 +00:00
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])
rows, err := db.Query(q)
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
// 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])
rows, err := db.Query(q)
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
// 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])
rows, err := db.QueryContext(context.Background(), q)
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
2021-05-07 17:04:01 +01:00
// 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])
rows, err := tx.QueryContext(context.Background(), q)
if err != nil {
panic(err)
}
defer rows.Close()
if err := tx.Commit(); err != nil {
panic(err)
}
}`}, 1, gosec.NewConfig()}, {[]string{`
2018-01-22 18:45:07 +00:00
// Format string false positive, safe string spec.
package main
2018-01-22 18:45:07 +00:00
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()
}`}, 0, gosec.NewConfig()}, {[]string{`
2017-12-28 06:54:10 +00:00
// Format string false positive
package main
2017-12-28 06:54:10 +00:00
import (
"database/sql"
)
const staticQuery = "SELECT * FROM foo WHERE age < 32"
2017-12-28 06:54:10 +00:00
func main(){
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
2017-12-28 06:54:10 +00:00
}
rows, err := db.Query(staticQuery)
if err != nil {
panic(err)
2017-12-28 06:54:10 +00:00
}
defer rows.Close()
}`}, 0, gosec.NewConfig()}, {[]string{`
// 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()
}`}, 0, gosec.NewConfig()}, {[]string{`
// 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()
}`}, 0, gosec.NewConfig()}, {[]string{`
package main
import (
"fmt"
)
func main(){
fmt.Sprintln()
}`}, 0, gosec.NewConfig()}, {[]string{`
// 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])
rows, err := db.Query(q)
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
// 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])
rows, err := db.Query(q)
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
// 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])
row := db.QueryRow(q)
err = row.Scan(&name)
if err != nil {
panic(err)
}
defer db.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
// 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])
err = db.QueryRow(q).Scan(&name)
if err != nil {
panic(err)
}
defer db.Close()
}`}, 1, gosec.NewConfig()}, {[]string{`
// 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])
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()
}
`}, 1, gosec.NewConfig()}, {[]string{`
// 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])
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()
}
`}, 1, gosec.NewConfig()}, {[]string{`
// 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()
}
`}, 0, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG202 - SQL query string building via string concatenation
SampleCodeG202 = []CodeSample{
{[]string{`
// 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] + "')"
rows, err := db.Query(q)
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()},
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"database/sql"
"os"
)
2017-12-28 06:54:10 +00:00
func main(){
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
}
rows, err := db.Query("SELECT * FROM foo WHERE name = " + os.Args[1])
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()},
{[]string{`
// case insensitive match
package main
import (
"database/sql"
"os"
)
func main(){
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
}
rows, err := db.Query("select * from foo where name = " + os.Args[1])
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()},
{[]string{`
// context match
package main
import (
"context"
"database/sql"
"os"
)
func main(){
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
}
rows, err := db.QueryContext(context.Background(), "select * from foo where name = " + os.Args[1])
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()},
{[]string{`
2021-05-07 17:04:01 +01:00
// 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()
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)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
// multiple string concatenation
package main
import (
"database/sql"
"os"
)
func main(){
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
}
rows, err := db.Query("SELECT * FROM foo" + "WHERE name = " + os.Args[1])
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 1, gosec.NewConfig()},
{[]string{`
2017-12-28 06:54:10 +00:00
// false positive
package main
2017-12-28 06:54:10 +00:00
import (
"database/sql"
)
2017-12-28 06:54:10 +00:00
var staticQuery = "SELECT * FROM foo WHERE age < "
func main(){
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
2017-12-28 06:54:10 +00:00
panic(err)
}
rows, err := db.Query(staticQuery + "32")
if err != nil {
panic(err)
}
defer rows.Close()
}`}, 0, gosec.NewConfig()},
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"database/sql"
)
2017-12-28 06:54:10 +00:00
const age = "32"
2017-12-28 06:54:10 +00:00
var staticQuery = "SELECT * FROM foo WHERE age < "
2017-12-28 06:54:10 +00:00
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()
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
const gender = "M"
`, `
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()
}
`}, 0, gosec.NewConfig()},
{[]string{`
// ExecContext match
package main
import (
"context"
"database/sql"
"fmt"
"os"
)
func main() {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
}
result, err := db.ExecContext(context.Background(), "select * from foo where name = "+os.Args[1])
if err != nil {
panic(err)
}
fmt.Println(result)
}`}, 1, gosec.NewConfig()},
{[]string{`
// Exec match
package main
import (
"database/sql"
"fmt"
"os"
)
func main() {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
}
result, err := db.Exec("select * from foo where name = " + os.Args[1])
if err != nil {
panic(err)
}
fmt.Println(result)
}`}, 1, gosec.NewConfig()},
{[]string{`
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)
}
`}, 0, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG203 - Template checks
SampleCodeG203 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
// We assume that hardcoded template strings are safe as the programmer would
// need to be explicitly shooting themselves in the foot (as below)
package main
2017-12-28 06:54:10 +00:00
import (
"html/template"
"os"
)
2017-12-28 06:54:10 +00:00
const tmpl = ""
2017-12-28 06:54:10 +00:00
func main() {
t := template.Must(template.New("ex").Parse(tmpl))
v := map[string]interface{}{
"Title": "Test <b>World</b>",
"Body": template.HTML("<script>alert(1)</script>"),
}
t.Execute(os.Stdout, v)
}`}, 0, gosec.NewConfig()}, {[]string{
2017-12-28 06:54:10 +00:00
`
// Using a variable to initialize could potentially be dangerous. Under the
// current model this will likely produce some false positives.
package main
2017-12-28 06:54:10 +00:00
import (
"html/template"
"os"
)
2017-12-28 06:54:10 +00:00
const tmpl = ""
2017-12-28 06:54:10 +00:00
func main() {
a := "something from another place"
t := template.Must(template.New("ex").Parse(tmpl))
v := map[string]interface{}{
"Title": "Test <b>World</b>",
"Body": template.HTML(a),
}
t.Execute(os.Stdout, v)
}`,
}, 1, gosec.NewConfig()}, {[]string{
2017-12-28 06:54:10 +00:00
`
package main
2017-12-28 06:54:10 +00:00
import (
"html/template"
"os"
)
2017-12-28 06:54:10 +00:00
const tmpl = ""
2017-12-28 06:54:10 +00:00
func main() {
a := "something from another place"
t := template.Must(template.New("ex").Parse(tmpl))
v := map[string]interface{}{
"Title": "Test <b>World</b>",
"Body": template.JS(a),
}
t.Execute(os.Stdout, v)
}`,
}, 1, gosec.NewConfig()}, {[]string{
2017-12-28 06:54:10 +00:00
`
package main
2017-12-28 06:54:10 +00:00
import (
"html/template"
"os"
)
2017-12-28 06:54:10 +00:00
const tmpl = ""
2017-12-28 06:54:10 +00:00
func main() {
a := "something from another place"
t := template.Must(template.New("ex").Parse(tmpl))
v := map[string]interface{}{
"Title": "Test <b>World</b>",
"Body": template.URL(a),
}
t.Execute(os.Stdout, v)
}`,
}, 1, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG204 - Subprocess auditing
SampleCodeG204 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"log"
"os/exec"
"context"
2017-12-28 06:54:10 +00:00
)
2017-12-28 06:54:10 +00:00
func main() {
2023-05-26 16:03:54 +01:00
err := exec.CommandContext(context.Background(), "git", "rev-parse", "--show-toplevel").Run()
2017-12-28 06:54:10 +00:00
if err != nil {
log.Fatal(err)
}
log.Printf("Command finished with error: %v", err)
}`}, 0, gosec.NewConfig()},
{[]string{`
// Calling any function which starts a new process with using
// command line arguments as it's arguments is considered dangerous
2017-12-28 06:54:10 +00:00
package main
import (
2021-01-01 19:45:13 +00:00
"context"
"log"
"os"
"os/exec"
)
func main() {
err := exec.CommandContext(context.Background(), os.Args[0], "5").Run()
if err != nil {
log.Fatal(err)
}
log.Printf("Command finished with error: %v", err)
}`}, 1, gosec.NewConfig()},
{[]string{`
// Initializing a local variable using a environmental
// variable is consider as a dangerous user input
package main
2017-12-28 06:54:10 +00:00
import (
"log"
"os"
"os/exec"
)
2017-12-28 06:54:10 +00:00
func main() {
run := "sleep" + os.Getenv("SOMETHING")
cmd := exec.Command(run, "5")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
log.Printf("Command finished with error: %v", err)
}`}, 1, gosec.NewConfig()},
{[]string{`
// gosec doesn't have enough context to decide that the
2023-05-26 16:03:54 +01:00
// command argument of the RunCmd function is hardcoded string
// and that's why it's better to warn the user so he can audit it
package main
import (
"log"
"os/exec"
)
func RunCmd(command string) {
cmd := exec.Command(command, "5")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
}
func main() {
RunCmd("sleep")
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"log"
"os/exec"
)
func RunCmd(a string, c string) {
cmd := exec.Command(c)
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
cmd = exec.Command(a)
err = cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
}
func main() {
RunCmd("ll", "ls")
}`}, 0, gosec.NewConfig()},
{[]string{`
2023-05-26 16:03:54 +01:00
// syscall.Exec function called with hardcoded arguments
// shouldn't be consider as a command injection
package main
import (
"fmt"
"syscall"
)
func main() {
err := syscall.Exec("/bin/cat", []string{"/etc/passwd"}, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}`}, 0, gosec.NewConfig()},
{
[]string{`
package main
import (
"fmt"
"syscall"
)
func RunCmd(command string) {
_, err := syscall.ForkExec(command, []string{}, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}
func main() {
RunCmd("sleep")
}`}, 1, gosec.NewConfig(),
},
{
[]string{`
package main
import (
"fmt"
"syscall"
)
func RunCmd(command string) {
2021-01-01 19:45:13 +00:00
_, _, err := syscall.StartProcess(command, []string{}, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}
func main() {
RunCmd("sleep")
}`}, 1, gosec.NewConfig(),
},
{[]string{`
// starting a process with a variable as an argument
// even if not constant is not considered as dangerous
2023-05-26 16:03:54 +01:00
// because it has hardcoded value
package main
import (
"log"
"os/exec"
)
func main() {
run := "sleep"
cmd := exec.Command(run, "5")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
log.Printf("Command finished with error: %v", err)
}`}, 0, gosec.NewConfig()},
{[]string{`
// exec.Command from supplemental package sys/execabs
// using variable arguments
package main
import (
"context"
"log"
"os"
exec "golang.org/x/sys/execabs"
)
func main() {
err := exec.CommandContext(context.Background(), os.Args[0], "5").Run()
if err != nil {
log.Fatal(err)
}
log.Printf("Command finished with error: %v", err)
}
`}, 1, gosec.NewConfig()},
{[]string{`
// Initializing a local variable using a environmental
// variable is consider as a dangerous user input
package main
import (
"log"
"os"
"os/exec"
)
func main() {
var run = "sleep" + os.Getenv("SOMETHING")
cmd := exec.Command(run, "5")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
log.Printf("Command finished with error: %v", err)
}`}, 1, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG301 - mkdir permission check
SampleCodeG301 = []CodeSample{{[]string{`
2017-12-28 06:54:10 +00:00
package main
import (
"fmt"
"os"
)
func main() {
err := os.Mkdir("/tmp/mydir", 0777)
if err != nil {
fmt.Println("Error when creating a directory!")
return
}
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"fmt"
"os"
)
func main() {
err := os.MkdirAll("/tmp/mydir", 0777)
if err != nil {
fmt.Println("Error when creating a directory!")
return
}
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"fmt"
"os"
)
2017-12-28 06:54:10 +00:00
func main() {
err := os.Mkdir("/tmp/mydir", 0600)
if err != nil {
fmt.Println("Error when creating a directory!")
return
}
}`}, 0, gosec.NewConfig()}}
2017-12-28 06:54:10 +00:00
// SampleCodeG302 - file create / chmod permissions check
SampleCodeG302 = []CodeSample{{[]string{`
2017-12-28 06:54:10 +00:00
package main
import (
"fmt"
"os"
)
func main() {
err := os.Chmod("/tmp/somefile", 0777)
if err != nil {
fmt.Println("Error when changing file permissions!")
return
}
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"fmt"
"os"
)
func main() {
_, err := os.OpenFile("/tmp/thing", os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
fmt.Println("Error opening a file!")
return
}
}`}, 1, gosec.NewConfig()}, {[]string{`
package main
import (
"fmt"
"os"
)
func main() {
err := os.Chmod("/tmp/mydir", 0400)
if err != nil {
fmt.Println("Error")
return
}
}`}, 0, gosec.NewConfig()}, {[]string{`
package main
import (
"fmt"
"os"
)
2017-12-28 06:54:10 +00:00
func main() {
_, err := os.OpenFile("/tmp/thing", os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
fmt.Println("Error opening a file!")
return
}
}
`}, 0, gosec.NewConfig()}}
2017-12-28 06:54:10 +00:00
// SampleCodeG303 - bad tempfile permissions & hardcoded shared path
SampleCodeG303 = []CodeSample{{[]string{`
2017-12-28 06:54:10 +00:00
package samples
2017-12-28 06:54:10 +00:00
import (
"fmt"
2017-12-28 06:54:10 +00:00
"io/ioutil"
"os"
"path"
"path/filepath"
2017-12-28 06:54:10 +00:00
)
2017-12-28 06:54:10 +00:00
func main() {
err := ioutil.WriteFile("/tmp/demo2", []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
f, err := os.Create("/tmp/demo2")
if err != nil {
fmt.Println("Error while writing!")
} else if err = f.Close(); err != nil {
fmt.Println("Error while closing!")
}
err = os.WriteFile("/tmp/demo2", []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
err = os.WriteFile("/usr/tmp/demo2", []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
err = os.WriteFile("/tmp/" + "demo2", []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
err = os.WriteFile(os.TempDir() + "/demo2", []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
err = os.WriteFile(path.Join("/var/tmp", "demo2"), []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
err = os.WriteFile(path.Join(os.TempDir(), "demo2"), []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
err = os.WriteFile(filepath.Join(os.TempDir(), "demo2"), []byte("This is some data"), 0644)
if err != nil {
fmt.Println("Error while writing!")
}
}`}, 9, gosec.NewConfig()}}
2017-12-28 06:54:10 +00:00
// SampleCodeG304 - potential file inclusion vulnerability
SampleCodeG304 = []CodeSample{
{[]string{`
package main
import (
"os"
"io/ioutil"
"log"
)
func main() {
f := os.Getenv("tainted_file")
body, err := ioutil.ReadFile(f)
if err != nil {
log.Printf("Error: %v\n", err)
}
log.Print(body)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"os"
"log"
)
func main() {
f := os.Getenv("tainted_file")
body, err := os.ReadFile(f)
if err != nil {
log.Printf("Error: %v\n", err)
}
log.Print(body)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
title := r.URL.Query().Get("title")
f, err := os.Open(title)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
body := make([]byte, 5)
2018-03-09 05:28:56 +00:00
if _, err = f.Read(body); err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Fprintf(w, "%s", body)
})
log.Fatal(http.ListenAndServe(":3000", nil))
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
title := r.URL.Query().Get("title")
f, err := os.OpenFile(title, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
body := make([]byte, 5)
if _, err = f.Read(body); err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Fprintf(w, "%s", body)
})
log.Fatal(http.ListenAndServe(":3000", nil))
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"log"
"os"
"io/ioutil"
)
func main() {
f2 := os.Getenv("tainted_file2")
body, err := ioutil.ReadFile("/tmp/" + f2)
if err != nil {
log.Printf("Error: %v\n", err)
}
log.Print(body)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"bufio"
"fmt"
"os"
"path/filepath"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Please enter file to read: ")
file, _ := reader.ReadString('\n')
file = file[:len(file)-1]
f, err := os.Open(filepath.Join("/tmp/service/", file))
if err != nil {
fmt.Printf("Error: %v\n", err)
}
contents := make([]byte, 15)
if _, err = f.Read(contents); err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Println(string(contents))
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"log"
"os"
"io/ioutil"
"path/filepath"
)
func main() {
dir := os.Getenv("server_root")
f3 := os.Getenv("tainted_file3")
// edge case where both a binary expression and file Join are used.
body, err := ioutil.ReadFile(filepath.Join("/var/"+dir, f3))
if err != nil {
log.Printf("Error: %v\n", err)
}
log.Print(body)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"os"
"path/filepath"
)
func main() {
repoFile := "path_of_file"
cleanRepoFile := filepath.Clean(repoFile)
2021-01-01 19:45:13 +00:00
_, err := os.OpenFile(cleanRepoFile, os.O_RDONLY, 0600)
if err != nil {
panic(err)
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"os"
"path/filepath"
)
func openFile(filePath string) {
2021-01-01 19:45:13 +00:00
_, err := os.OpenFile(filepath.Clean(filePath), os.O_RDONLY, 0600)
if err != nil {
panic(err)
}
}
func main() {
repoFile := "path_of_file"
openFile(repoFile)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"os"
"path/filepath"
)
func openFile(dir string, filePath string) {
fp := filepath.Join(dir, filePath)
fp = filepath.Clean(fp)
_, err := os.OpenFile(fp, os.O_RDONLY, 0600)
if err != nil {
panic(err)
}
}
func main() {
repoFile := "path_of_file"
dir := "path_of_dir"
openFile(dir, repoFile)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"os"
"path/filepath"
)
func main() {
repoFile := "path_of_file"
relFile, err := filepath.Rel("./", repoFile)
if err != nil {
panic(err)
}
_, err = os.OpenFile(relFile, os.O_RDONLY, 0600)
if err != nil {
panic(err)
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"io"
"os"
)
func createFile(file string) *os.File {
f, err := os.Create(file)
if err != nil {
panic(err)
}
return f
}
func main() {
s, err := os.Open("src")
if err != nil {
panic(err)
}
defer s.Close()
d := createFile("dst")
defer d.Close()
_, err = io.Copy(d, s)
if err != nil {
panic(err)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
"path/filepath"
)
type foo struct {
}
func (f *foo) doSomething(silly string) error {
whoCares, err := filepath.Rel(THEWD, silly)
if err != nil {
return err
}
fmt.Printf("%s", whoCares)
return nil
}
func main() {
f := &foo{}
if err := f.doSomething("irrelevant"); err != nil {
panic(err)
}
}
`, `
package main
var THEWD string
`}, 0, gosec.NewConfig()},
}
// SampleCodeG305 - File path traversal when extracting zip/tar archives
SampleCodeG305 = []CodeSample{{[]string{`
package unzip
import (
"archive/zip"
"io"
"os"
"path/filepath"
)
func unzip(archive, target string) error {
reader, err := zip.OpenReader(archive)
if err != nil {
return err
}
if err := os.MkdirAll(target, 0750); err != nil {
return err
}
for _, file := range reader.File {
path := filepath.Join(target, file.Name)
if file.FileInfo().IsDir() {
os.MkdirAll(path, file.Mode()) //#nosec
continue
}
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close()
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer targetFile.Close()
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
return nil
}`}, 1, gosec.NewConfig()}, {[]string{`
package unzip
import (
"archive/zip"
"io"
"os"
"path/filepath"
)
func unzip(archive, target string) error {
reader, err := zip.OpenReader(archive)
if err != nil {
return err
}
if err := os.MkdirAll(target, 0750); err != nil {
return err
}
for _, file := range reader.File {
archiveFile := file.Name
path := filepath.Join(target, archiveFile)
if file.FileInfo().IsDir() {
os.MkdirAll(path, file.Mode()) //#nosec
continue
}
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close()
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer targetFile.Close()
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
return nil
}`}, 1, gosec.NewConfig()}, {[]string{`
package zip
import (
"archive/zip"
"io"
"os"
"path"
)
func extractFile(f *zip.File, destPath string) error {
filePath := path.Join(destPath, f.Name)
os.MkdirAll(path.Dir(filePath), os.ModePerm)
rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()
fw, err := os.Create(filePath)
if err != nil {
return err
}
defer fw.Close()
if _, err = io.Copy(fw, rc); err != nil {
return err
}
if f.FileInfo().Mode()&os.ModeSymlink != 0 {
return nil
}
if err = os.Chtimes(filePath, f.ModTime(), f.ModTime()); err != nil {
return err
}
return os.Chmod(filePath, f.FileInfo().Mode())
}`}, 1, gosec.NewConfig()}, {[]string{`
package tz
import (
"archive/tar"
"io"
"os"
"path"
)
func extractFile(f *tar.Header, tr *tar.Reader, destPath string) error {
filePath := path.Join(destPath, f.Name)
os.MkdirAll(path.Dir(filePath), os.ModePerm)
fw, err := os.Create(filePath)
if err != nil {
return err
}
defer fw.Close()
if _, err = io.Copy(fw, tr); err != nil {
return err
}
if f.FileInfo().Mode()&os.ModeSymlink != 0 {
return nil
}
if err = os.Chtimes(filePath, f.FileInfo().ModTime(), f.FileInfo().ModTime()); err != nil {
return err
}
return os.Chmod(filePath, f.FileInfo().Mode())
2020-02-28 11:48:18 +00:00
}`}, 1, gosec.NewConfig()}}
// SampleCodeG306 - Poor permissions for WriteFile
SampleCodeG306 = []CodeSample{
{[]string{`package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
2020-02-28 11:48:18 +00:00
d1 := []byte("hello\ngo\n")
err := ioutil.WriteFile("/tmp/dat1", d1, 0744)
check(err)
allowed := ioutil.WriteFile("/tmp/dat1", d1, 0600)
check(allowed)
2020-02-28 11:48:18 +00:00
f, err := os.Create("/tmp/dat2")
check(err)
2020-02-28 11:48:18 +00:00
defer f.Close()
2020-02-28 11:48:18 +00:00
d2 := []byte{115, 111, 109, 101, 10}
n2, err := f.Write(d2)
defer check(err)
fmt.Printf("wrote %d bytes\n", n2)
n3, err := f.WriteString("writes\n")
fmt.Printf("wrote %d bytes\n", n3)
f.Sync()
w := bufio.NewWriter(f)
n4, err := w.WriteString("buffered\n")
fmt.Printf("wrote %d bytes\n", n4)
w.Flush()
}`}, 1, gosec.NewConfig()},
}
// SampleCodeG307 - Poor permissions for os.Create
SampleCodeG307 = []CodeSample{
{[]string{`package main
import (
"fmt"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
f, err := os.Create("/tmp/dat2")
check(err)
defer f.Close()
}`}, 0, gosec.NewConfig()},
{[]string{`package main
import (
"fmt"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
f, err := os.Create("/tmp/dat2")
check(err)
defer f.Close()
}`}, 1, gosec.Config{"G307": "0o600"}},
}
// SampleCodeG401 - Use of weak crypto MD5
SampleCodeG401 = []CodeSample{
{[]string{`
package main
import (
"crypto/md5"
"fmt"
"io"
"log"
"os"
)
func main() {
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
defer func() {
err := f.Close()
if err != nil {
log.Printf("error closing the file: %s", err)
}
}()
h := md5.New()
if _, err := io.Copy(h, f); err != nil {
log.Fatal(err)
}
fmt.Printf("%x", h.Sum(nil))
}`}, 1, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
2018-08-08 15:38:57 +01:00
// SampleCodeG401b - Use of weak crypto SHA1
SampleCodeG401b = []CodeSample{
{[]string{`
2018-08-08 15:38:57 +01:00
package main
2018-08-08 15:38:57 +01:00
import (
"crypto/sha1"
"fmt"
"io"
"log"
"os"
)
func main() {
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
h := sha1.New()
if _, err := io.Copy(h, f); err != nil {
log.Fatal(err)
}
fmt.Printf("%x", h.Sum(nil))
}`}, 1, gosec.NewConfig()},
}
2018-08-08 15:38:57 +01:00
2017-12-28 06:54:10 +00:00
// SampleCodeG402 - TLS settings
SampleCodeG402 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
// InsecureSkipVerify
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/tls"
"fmt"
"net/http"
)
2017-12-28 06:54:10 +00:00
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
_, err := client.Get("https://golang.org/")
if err != nil {
fmt.Println(err)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
// InsecureSkipVerify from variable
package main
import (
"crypto/tls"
)
func main() {
var conf tls.Config
conf.InsecureSkipVerify = true
}`}, 1, gosec.NewConfig()},
{[]string{
`
2017-12-28 06:54:10 +00:00
// Insecure minimum version
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/tls"
"fmt"
"net/http"
)
2017-12-28 06:54:10 +00:00
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{MinVersion: 0},
}
client := &http.Client{Transport: tr}
_, err := client.Get("https://golang.org/")
if err != nil {
fmt.Println(err)
}
}`,
}, 1, gosec.NewConfig()},
{[]string{
`
// Insecure minimum version
package main
import (
"crypto/tls"
"fmt"
)
func CaseNotError() *tls.Config {
var v uint16 = tls.VersionTLS13
return &tls.Config{
MinVersion: v,
}
}
func main() {
a := CaseNotError()
fmt.Printf("Debug: %v\n", a.MinVersion)
}`,
}, 0, gosec.NewConfig()},
{[]string{
`
// Insecure minimum version
package main
import (
"crypto/tls"
"fmt"
)
func CaseNotError() *tls.Config {
return &tls.Config{
MinVersion: tls.VersionTLS13,
}
}
func main() {
a := CaseNotError()
fmt.Printf("Debug: %v\n", a.MinVersion)
}`,
}, 0, gosec.NewConfig()},
{[]string{
`
// Insecure minimum version
package main
import (
"crypto/tls"
"fmt"
)
func CaseError() *tls.Config {
var v = &tls.Config{
MinVersion: 0,
}
return v
}
func main() {
a := CaseError()
fmt.Printf("Debug: %v\n", a.MinVersion)
}`,
}, 1, gosec.NewConfig()},
{[]string{
`
// Insecure minimum version
package main
import (
"crypto/tls"
"fmt"
)
func CaseError() *tls.Config {
var v = &tls.Config{
MinVersion: getVersion(),
}
return v
}
func getVersion() uint16 {
return tls.VersionTLS12
}
func main() {
a := CaseError()
fmt.Printf("Debug: %v\n", a.MinVersion)
}`,
}, 1, gosec.NewConfig()},
{[]string{
`
// Insecure minimum version
package main
import (
"crypto/tls"
"fmt"
"net/http"
)
var theValue uint16 = 0x0304
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{MinVersion: theValue},
}
client := &http.Client{Transport: tr}
_, err := client.Get("https://golang.org/")
if err != nil {
fmt.Println(err)
}
}
`,
}, 0, gosec.NewConfig()},
{[]string{`
2017-12-28 06:54:10 +00:00
// Insecure max version
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/tls"
"fmt"
"net/http"
)
2017-12-28 06:54:10 +00:00
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{MaxVersion: 0},
}
client := &http.Client{Transport: tr}
_, err := client.Get("https://golang.org/")
if err != nil {
fmt.Println(err)
}
}
`}, 1, gosec.NewConfig()},
{
[]string{`
2017-12-28 06:54:10 +00:00
// Insecure ciphersuite selection
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/tls"
"fmt"
"net/http"
)
2017-12-28 06:54:10 +00:00
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{CipherSuites: []uint16{
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
2017-12-28 06:54:10 +00:00
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
},},
}
client := &http.Client{Transport: tr}
_, err := client.Get("https://golang.org/")
if err != nil {
fmt.Println(err)
}
}`}, 1, gosec.NewConfig(),
},
{[]string{`
// secure max version when min version is specified
package main
import (
"crypto/tls"
"fmt"
"net/http"
)
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{MaxVersion: 0, MinVersion: tls.VersionTLS13},
}
client := &http.Client{Transport: tr}
_, err := client.Get("https://golang.org/")
if err != nil {
fmt.Println(err)
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package p0
import "crypto/tls"
func TlsConfig0() *tls.Config {
var v uint16 = 0
return &tls.Config{MinVersion: v}
}
`, `
package p0
import "crypto/tls"
func TlsConfig1() *tls.Config {
return &tls.Config{MinVersion: 0x0304}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"crypto/tls"
"fmt"
)
func main() {
cfg := tls.Config{
MinVersion: MinVer,
}
fmt.Println("tls min version", cfg.MinVersion)
}
`, `
package main
import "crypto/tls"
const MinVer = tls.VersionTLS13
`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"crypto/tls"
cryptotls "crypto/tls"
)
func main() {
_ = tls.Config{MinVersion: tls.VersionTLS12}
_ = cryptotls.Config{MinVersion: cryptotls.VersionTLS12}
}
`}, 0, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG403 - weak key strength
SampleCodeG403 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/rand"
"crypto/rsa"
"fmt"
)
2017-12-28 06:54:10 +00:00
func main() {
//Generate Private Key
pvk, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
fmt.Println(err)
}
fmt.Println(pvk)
}`}, 1, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG404 - weak random number
SampleCodeG404 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import "crypto/rand"
2017-12-28 06:54:10 +00:00
func main() {
good, _ := rand.Read(nil)
println(good)
}`}, 0, gosec.NewConfig()},
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import "math/rand"
2017-12-28 06:54:10 +00:00
func main() {
bad := rand.Int()
println(bad)
}`}, 1, gosec.NewConfig()},
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/rand"
mrand "math/rand"
)
2017-12-28 06:54:10 +00:00
func main() {
good, _ := rand.Read(nil)
println(good)
bad := mrand.Int31()
println(bad)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"math/rand"
)
func main() {
2021-01-01 19:45:13 +00:00
gen := rand.New(rand.NewSource(10))
bad := gen.Int()
println(bad)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"math/rand"
)
func main() {
bad := rand.Intn(10)
println(bad)
}`}, 1, gosec.NewConfig()},
Fix false positives for G404 with aliased packages It appears that `GetImportedName` returns _both_ aliased and non-aliased imports. As a result, a file having both crypto/rand and math/rand (but aliased) would trigger false positives on G404. Given the following file; ```go package main import ( "crypto/rand" "math/big" rnd "math/rand" ) func main() { _, _ = rand.Int(rand.Reader, big.NewInt(int64(2))) _ = rnd.Intn(2) } ``` And patching for debugging; ```patch diff --git a/helpers.go b/helpers.go index 437d032..80f4233 100644 --- a/helpers.go +++ b/helpers.go @@ -250,6 +250,8 @@ func GetBinaryExprOperands(be *ast.BinaryExpr) []ast.Node { // GetImportedName returns the name used for the package within the // code. It will ignore initialization only imports. func GetImportedName(path string, ctx *Context) (string, bool) { + fmt.Printf("%+v", ctx.Imports.Imported) + os.Exit(1) importName, imported := ctx.Imports.Imported[path] if !imported { return "", false ``` Would show that `math/rand` was included in the list, using it's non-aliased name (`:rand`). gosec -quiet . map[crypto/rand:rand math/big:big math/rand:rand] This patch works around this problem by reversing the order in which imports are resolved in `MatchCallByPackage()`. Aliased packages are tried first, after which non-aliased imports are tried. Given the example application mentioned above: Before this patch: ```bash gosec -quiet . Results: [/Users/sebastiaan/Projects/test/gosec-issue/main.go:10] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 9: func main() { > 10: _, _ = rand.Int(rand.Reader, big.NewInt(int64(2))) 11: _ = rnd.Intn(2) ``` With this patch applied: ```bash gosec --quiet . Results: [/Users/sebastiaan/Projects/test/gosec-issue/main.go:11] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 10: _, _ = rand.Int(rand.Reader, big.NewInt(int64(2))) > 11: _ = rnd.Intn(2) 12: } ``` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-09-04 15:32:03 +01:00
{[]string{`
package main
import (
"crypto/rand"
"math/big"
rnd "math/rand"
)
func main() {
good, _ := rand.Int(rand.Reader, big.NewInt(int64(2)))
println(good)
bad := rnd.Intn(2)
println(bad)
}
`}, 1, gosec.NewConfig()},
Refactor to support duplicate imports with different aliases (#865) The existing code assumed imports to be either imported, or imported with an alias. Badly formatted files may have duplicate imports for a package, using different aliases. This patch refactors the code, and; Introduces a new `GetImportedNames` function, which returns all name(s) and aliase(s) for a package, which effectively combines `GetAliasedName` and `GetImportedName`, but adding support for duplicate imports. The old `GetAliasedName` and `GetImportedName` functions have been rewritten to use the new function and marked deprecated, but could be removed if there are no external consumers. With this patch, the linter is able to detect issues in files such as; package main import ( crand "crypto/rand" "math/big" "math/rand" rand2 "math/rand" rand3 "math/rand" ) func main() { _, _ = crand.Int(crand.Reader, big.NewInt(int64(2))) // good _ = rand.Intn(2) // bad _ = rand2.Intn(2) // bad _ = rand3.Intn(2) // bad } Before this patch, only a single issue would be detected: gosec --quiet . [main.go:14] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 13: > 14: _ = rand.Intn(2) // bad 15: _ = rand2.Intn(2) // bad With this patch, all issues are identified: gosec --quiet . [main.go:16] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 15: _ = rand2.Intn(2) // bad > 16: _ = rand3.Intn(2) // bad 17: } [main.go:15] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 14: _ = rand.Intn(2) // bad > 15: _ = rand2.Intn(2) // bad 16: _ = rand3.Intn(2) // bad [main.go:14] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 13: > 14: _ = rand.Intn(2) // bad 15: _ = rand2.Intn(2) // bad While working on this change, I noticed that ImportTracker.TrackFile() was not able to find import aliases; Analyser.Check() called both ImportTracker.TrackFile() and ast.Walk(), which (with the updated ImportTracker) resulted in importes to be in- correctly included multiple times (once with the correct alias, once with the default). I updated ImportTracker.TrackFile() to fix this, but with the updated ImportTracker, Analyser.Check() no longer has to call ImportTracker.TrackFile() separately, as ast.Walk() already handles the file, and will find all imports. Signed-off-by: Sebastiaan van Stijn <github@gone.nl> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-10-17 09:59:18 +01:00
{[]string{`
package main
import (
crand "crypto/rand"
"math/big"
"math/rand"
rand2 "math/rand"
rand3 "math/rand"
)
func main() {
_, _ = crand.Int(crand.Reader, big.NewInt(int64(2))) // good
_ = rand.Intn(2) // bad
_ = rand2.Intn(2) // bad
_ = rand3.Intn(2) // bad
}
`}, 3, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG501 - Blocklisted import MD5
2017-12-28 06:54:10 +00:00
SampleCodeG501 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/md5"
"fmt"
"os"
)
2017-12-28 06:54:10 +00:00
func main() {
for _, arg := range os.Args {
fmt.Printf("%x - %s\n", md5.Sum([]byte(arg)), arg)
}
}`}, 1, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG502 - Blocklisted import DES
2017-12-28 06:54:10 +00:00
SampleCodeG502 = []CodeSample{
{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/cipher"
"crypto/des"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
)
2017-12-28 06:54:10 +00:00
func main() {
block, err := des.NewCipher([]byte("sekritz"))
if err != nil {
panic(err)
}
plaintext := []byte("I CAN HAZ SEKRIT MSG PLZ")
ciphertext := make([]byte, des.BlockSize+len(plaintext))
iv := ciphertext[:des.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[des.BlockSize:], plaintext)
fmt.Println("Secret message is: %s", hex.EncodeToString(ciphertext))
}`}, 1, gosec.NewConfig()},
}
2017-12-28 06:54:10 +00:00
// SampleCodeG503 - Blocklisted import RC4
SampleCodeG503 = []CodeSample{{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"crypto/rc4"
"encoding/hex"
"fmt"
)
2017-12-28 06:54:10 +00:00
func main() {
cipher, err := rc4.NewCipher([]byte("sekritz"))
if err != nil {
panic(err)
}
plaintext := []byte("I CAN HAZ SEKRIT MSG PLZ")
ciphertext := make([]byte, len(plaintext))
cipher.XORKeyStream(ciphertext, plaintext)
fmt.Println("Secret message is: %s", hex.EncodeToString(ciphertext))
}`}, 1, gosec.NewConfig()}}
2017-12-28 06:54:10 +00:00
// SampleCodeG504 - Blocklisted import CGI
SampleCodeG504 = []CodeSample{{[]string{`
2017-12-28 06:54:10 +00:00
package main
2017-12-28 06:54:10 +00:00
import (
"net/http/cgi"
"net/http"
)
2017-12-28 06:54:10 +00:00
func main() {
cgi.Serve(http.FileServer(http.Dir("/usr/share/doc")))
}`}, 1, gosec.NewConfig()}}
// SampleCodeG505 - Blocklisted import SHA1
2018-08-08 15:38:57 +01:00
SampleCodeG505 = []CodeSample{
{[]string{`
2018-08-08 15:38:57 +01:00
package main
2018-08-08 15:38:57 +01:00
import (
"crypto/sha1"
"fmt"
"os"
)
2018-08-08 15:38:57 +01:00
func main() {
for _, arg := range os.Args {
fmt.Printf("%x - %s\n", sha1.Sum([]byte(arg)), arg)
}
}`}, 1, gosec.NewConfig()},
}
// SampleCodeG601 - Implicit aliasing over range statement
SampleCodeG601 = []CodeSample{
{[]string{
`
package main
import "fmt"
var vector []*string
func appendVector(s *string) {
vector = append(vector, s)
}
func printVector() {
for _, item := range vector {
fmt.Printf("%s", *item)
}
fmt.Println()
}
func foo() (int, **string, *string) {
for _, item := range vector {
return 0, &item, item
}
return 0, nil, nil
}
func main() {
for _, item := range []string{"A", "B", "C"} {
appendVector(&item)
}
printVector()
zero, c_star, c := foo()
2021-01-01 19:45:13 +00:00
fmt.Printf("%d %v %s", zero, c_star, c)
}`,
}, 1, gosec.NewConfig()},
{[]string{`
// see: github.com/securego/gosec/issues/475
package main
import (
"fmt"
)
func main() {
sampleMap := map[string]string{}
sampleString := "A string"
for sampleString, _ = range sampleMap {
fmt.Println(sampleString)
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type sampleStruct struct {
name string
}
func main() {
samples := []sampleStruct{
{name: "a"},
{name: "b"},
}
for _, sample := range samples {
fmt.Println(sample.name)
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type sampleStruct struct {
name string
}
func main() {
samples := []*sampleStruct{
{name: "a"},
{name: "b"},
}
for _, sample := range samples {
fmt.Println(&sample)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type sampleStruct struct {
name string
}
func main() {
samples := []*sampleStruct{
{name: "a"},
{name: "b"},
}
for _, sample := range samples {
fmt.Println(&sample.name)
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type sampleStruct struct {
name string
}
func main() {
samples := []sampleStruct{
{name: "a"},
{name: "b"},
}
for _, sample := range samples {
fmt.Println(&sample.name)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type subStruct struct {
name string
}
type sampleStruct struct {
sub subStruct
}
func main() {
samples := []sampleStruct{
{sub: subStruct{name: "a"}},
{sub: subStruct{name: "b"}},
}
for _, sample := range samples {
fmt.Println(&sample.sub.name)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type subStruct struct {
name string
}
type sampleStruct struct {
sub subStruct
}
func main() {
samples := []*sampleStruct{
{sub: subStruct{name: "a"}},
{sub: subStruct{name: "b"}},
}
for _, sample := range samples {
fmt.Println(&sample.sub.name)
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
func main() {
one, two := 1, 2
samples := []*int{&one, &two}
for _, sample := range samples {
fmt.Println(&sample)
}
}`}, 1, gosec.NewConfig()},
}
// SampleCodeBuildTag - G601 build tags
SampleCodeBuildTag = []CodeSample{{[]string{`
// +build tag
package main
func main() {
fmt.Println("no package imported error")
}`}, 1, gosec.NewConfig()}}
// SampleCodeCgo - Cgo file sample
SampleCodeCgo = []CodeSample{{[]string{`
package main
import (
"fmt"
"unsafe"
)
/*
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int printData(unsigned char *data) {
return printf("cData: %lu \"%s\"\n", (long unsigned int)strlen(data), data);
}
*/
import "C"
func main() {
// Allocate C data buffer.
width, height := 8, 2
lenData := width * height
// add string terminating null byte
cData := (*C.uchar)(C.calloc(C.size_t(lenData+1), C.sizeof_uchar))
// When no longer in use, free C allocations.
defer C.free(unsafe.Pointer(cData))
// Go slice reference to C data buffer,
// minus string terminating null byte
gData := (*[1 << 30]byte)(unsafe.Pointer(cData))[:lenData:lenData]
// Write and read cData via gData.
for i := range gData {
gData[i] = '.'
}
copy(gData[0:], "Data")
gData[len(gData)-1] = 'X'
fmt.Printf("gData: %d %q\n", len(gData), gData)
C.printData(cData)
}
`}, 0, gosec.NewConfig()}}
// SampleCodeG602 - Slice access out of bounds
SampleCodeG602 = []CodeSample{
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
fmt.Println(s[:3])
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
fmt.Println(s[3:])
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 16)
fmt.Println(s[:17])
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 16)
fmt.Println(s[:16])
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 16)
fmt.Println(s[5:17])
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 4)
fmt.Println(s[3])
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 4)
fmt.Println(s[5])
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
s = make([]byte, 3)
fmt.Println(s[:3])
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
fmt.Println(s[:3])
fmt.Println(s[3])
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
fmt.Println(s[:5])
fmt.Println(s[7])
}`}, 2, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0, 4)
x := s[:2]
y := x[:10]
fmt.Println(y)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]int, 0, 4)
doStuff(s)
}
func doStuff(x []int) {
newSlice := x[:10]
fmt.Println(newSlice)
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]int, 0, 30)
doStuff(s)
x := make([]int, 20)
y := x[10:]
doStuff(y)
z := y[5:]
doStuff(z)
}
func doStuff(x []int) {
newSlice := x[:10]
fmt.Println(newSlice)
newSlice2 := x[:6]
fmt.Println(newSlice2)
}`}, 2, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
testMap := make(map[string]any, 0)
testMap["test1"] = map[string]interface{}{
"test2": map[string]interface{}{
"value": 0,
},
}
fmt.Println(testMap)
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
fmt.Println(s[0])
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]byte, 0)
if len(s) > 0 {
fmt.Println("fake test")
}
fmt.Println(s[0])
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import "fmt"
func main() {
s := make([]int, 16)
for i := 0; i < 17; i++ {
s = append(s, i)
}
if len(s) < 16 {
fmt.Println(s[10:16])
} else {
fmt.Println(s[3:18])
}
fmt.Println(s[0])
for i := range s {
fmt.Println(s[i])
}
}`}, 0, gosec.NewConfig()},
}
)