Giter Site home page Giter Site logo

gokart's Introduction

GoKart - Go Security Static Analysis

CI Release

GoKart is a static analysis tool for Go that finds vulnerabilities using the SSA (single static assignment) form of Go source code. It is capable of tracing the source of variables and function arguments to determine whether input sources are safe, which reduces the number of false positives compared to other Go security scanners. For instance, a SQL query that is concatenated with a variable might traditionally be flagged as SQL injection; however, GoKart can figure out if the variable is actually a constant or constant equivalent, in which case there is no vulnerability.

GoKart also helps to power Chariot, Praetorian's security platform that helps you find, manage, and fix vulnerabilities in your source code and cloud environments. Chariot makes it simple to run automated, continuous GoKart scans on your source code. If you want to try GoKart, you can set up a free Chariot account in minutes by clicking here.

Why We Built GoKart

Static analysis is a powerful technique for finding vulnerabilities in source code. However, the approach has suffered from being noisy - that is, many static analysis tools find quite a few "vulnerabilities" that are not actually real. This has led to developer friction as users get tired of the tools "crying wolf" one time too many.

The motivation for GoKart was to address this: could we create a scanner with significantly lower false positive rates than existing tools? Based on our experimentation the answer is yes. By leveraging source-to-sink tracing and SSA, GoKart is capable of tracking variable taint between variable assignments, significantly improving the accuracy of findings. Our focus is on usability: pragmatically, that means we have optimized our approaches to reduce false alarms.

For more information, please read our blog post.

Install

You can install GoKart locally by using any one of the options listed below.

Install with go install

$ go install github.com/praetorian-inc/gokart@latest

Install a release binary

  1. Download the binary for your OS from the releases page.

  2. (OPTIONAL) Download the checksums.txt file to verify the integrity of the archive

# Check the checksum of the downloaded archive
$ shasum -a 256 gokart_${VERSION}_${ARCH}.tar.gz
b05c4d7895be260aa16336f29249c50b84897dab90e1221c9e96af9233751f22  gokart_${VERSION}_${ARCH}.tar.gz

$ cat gokart_${VERSION}_${ARCH}_checksums.txt | grep gokart_${VERSION}_${ARCH}.tar.gz
b05c4d7895be260aa16336f29249c50b84897dab90e1221c9e96af9233751f22  gokart_${VERSION}_${ARCH}.tar.gz
  1. Extract the downloaded archive
$ tar -xvf gokart_${VERSION}_${ARCH}.tar.gz
  1. Move the gokart binary into your path:
$ mv ./gokart /usr/local/bin/

Clone and build yourself

# clone the GoKart repo
$ git clone https://github.com/praetorian-inc/gokart.git

# navigate into the repo directory and build
$ cd gokart
$ go build

# Move the gokart binary into your path
$ mv ./gokart /usr/local/bin

Docker Support

Build the docker image

docker build -t gokart .

Running the container with a local scan (the local scan directory needs to be mounted to the container image)

docker run -v /path/to/scan-dir:/scan-dir gokart scan /scan-dir

Running the container with a remote scan (when specifying a private key for auth, that will also need to be mounted to the container)

docker run gokart scan -r https://github.com/praetorian-inc/gokart

# specifying a private key for private repository ssh authentication
docker run -v /path/to/key-dir/:/key-dir gokart scan -r [email protected]:praetorian-inc/gokart.git -k /key-dir/ssh_key

Usage

Run GoKart on a Go module in the current directory

# running without a directory specified defaults to '.'
gokart scan <flags>

Scan a Go module in a different directory

gokart scan <directory> <flags> 

Get Help

gokart help

Getting Started - Scanning an Example App

You can follow the steps below to run GoKart on Go Test Bench, an intentionally vulnerable Go application from the Contrast Security team.

# Clone sample vulnerable application
git clone https://github.com/Contrast-Security-OSS/go-test-bench.git
gokart scan go-test-bench/

Output should show some identified vulnerabilities, each with a Vulnerable Function and Source of User Input identified.

To test some additional GoKart features, you can scan with the CLI flags suggested below.

# Use verbose flag to show full traces of these vulnerabilities
gokart scan go-test-bench/ -v

# Use globalsTainted flag to ignore whitelisted Sources
# may increase false positive results
gokart scan go-test-bench/ -v -g

# Use debug flag to display internal analysis information
# which is useful for development and debugging
gokart scan go-test-bench/ -d

# Output results in sarif format
gokart scan go-test-bench/ -s

# Output results to file
gokart scan go-test-bench/ -o gokart-go-test-bench.txt

# Output scarif results to file
gokart scan go-test-bench/ -o gokart-go-test-bench.txt -s

# Scan remote public repository 
# Repository will be cloned locally, scanned and deleted afterwards
gokart scan -r https://github.com/ShiftLeftSecurity/shiftleft-go-demo -v

# Specify the remote branch to scan
gokart scan -r https://github.com/ShiftLeftSecurity/shiftleft-go-demo -b actions_fix

# Scan remote private repository via ssh
gokart scan -r [email protected]:Contrast-Security-OSS/go-test-bench.git 

# Scan remote private repository and optionally specify a key for ssh authentication 
gokart scan -r [email protected]:Contrast-Security-OSS/go-test-bench.git -k /home/gokart/.ssh/github_rsa_key

# Use remote scan and output flags together for seamless security reviews
gokart scan -r https://github.com/ShiftLeftSecurity/shiftleft-go-demo -o gokart-shiftleft-go-demo.txt -v 

# Use remote scan, output and sarif flags for frictionless integration into CI/CD
gokart scan -r https://github.com/ShiftLeftSecurity/shiftleft-go-demo -o gokart-shiftleft-go-demo.txt -s

To test out the extensibility of GoKart, you can modify the configuration file that GoKart uses to introduce a new vulnerable sink into analysis. There is a Test Sink analyzer defined in the included default config file at util/analyzers.yml. Modify util/analyzers.yml to remove the comments on the Test Sink analyzer and then direct GoKart to use the modified config file with the -i flag.

# Scan using modified analyzers.yml file and output full traces
gokart scan go-test-bench/ -v -i <path-to-gokart>/util/analyzers.yml

Output should now contain additional vulnerabilities, including new "Test Sink reachable by user input" vulnerabilities.

Run GoKart Tests

You can run the included tests with the following command, invoked from the GoKart root directory.

go test -v ./...

gokart's People

Contributors

adadkins avatar bpsizemore avatar bradlarsen avatar gssbzn avatar isp1r0 avatar jessesomerville avatar luckyc4t avatar michaelweber avatar praetorian-harry avatar praetorian-thendrickson avatar trumankain avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gokart's Issues

gokart fails after update to Go 1.20

After updating to Go 1.20 I get the following error:
running gokart version 0.5.1.

Using config found at /home/john/.gokart/analyzers.yml

Revving engines VRMMM VRMMM
3...2...1...Go!
panic: no concrete method: func (*regexp/syntax.Inst).MatchEmptyWidth(before rune, after rune) bool

goroutine 1 [running]:
golang.org/x/tools/go/ssa.(*Program).declaredFunc(0xc0013546c0, 0xc001190420)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:149 +0xf9
golang.org/x/tools/go/ssa.(*Program).originFunc(0xc0002e5e50?, 0x40d907?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/source.go:193 +0x32
golang.org/x/tools/go/ssa.(*Program).addMethod(0xc0013546c0, 0xc001333100, 0xc0002e5e50, 0xa77ac0?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:109 +0x169
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc001324550?}, 0x0, 0x1046368?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:200 +0x87f
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b010?, 0xc0004e1c80?}, 0x1, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:255 +0x6b6
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af70?, 0xc001611490?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:248 +0x589
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc001324570?}, 0x0, 0x1046368?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:220 +0x5d1
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b010?, 0xc0004e1ce0?}, 0x1, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:255 +0x6b6
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af70?, 0xc001611420?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:248 +0x589
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7afe8?, 0xc001324580?}, 0x0, 0x1046368?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:223 +0x37b
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b010?, 0xc0004e1d40?}, 0x1, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:255 +0x6b6
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af70?, 0xc0016113b0?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:248 +0x589
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc001324690?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:220 +0x5d1
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b038?, 0xc00141c4f8?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:260 +0x7f5
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc0013246e0?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:208 +0x1d0
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b038?, 0xc00141c528?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:260 +0x7f5
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc001324ea0?}, 0x0, 0x1046368?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:209 +0x1f7
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b010?, 0xc0004e1ef0?}, 0x1, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:255 +0x6b6
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af70?, 0xc001610c40?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:248 +0x589
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc001325510?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:220 +0x5d1
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b038?, 0xc00141d758?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:260 +0x7f5
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc001332630?}, 0x0, 0x1046368?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:209 +0x1f7
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b010?, 0xc0013c84e0?}, 0x1, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:255 +0x6b6
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af70?, 0xc0013d6000?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:248 +0x589
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7af98?, 0xc001332c60?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:220 +0x5d1
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7b038?, 0xc00143c600?}, 0x0, 0x1046360?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:260 +0x7f5
golang.org/x/tools/go/ssa.(*Program).needMethods(0xc0013546c0, {0xc7afc0?, 0xc001496b00?}, 0x0, 0x90349e?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:237 +0x33e
golang.org/x/tools/go/ssa.(*Program).needMethodsOf(0xc0013546c0, {0xc7afc0?, 0xc001496b00?}, 0x9ba9af?)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/methods.go:172 +0x7f
golang.org/x/tools/go/ssa.(*Package).build(0xc001313880)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/builder.go:2427 +0x133
sync.(*Once).doSlow(0xc0013546c0?, 0xc0008d1b80?)
        /opt/hostedtoolcache/go/1.19.1/x64/src/sync/once.go:74 +0xc2
sync.(*Once).Do(...)
        /opt/hostedtoolcache/go/1.19.1/x64/src/sync/once.go:65
golang.org/x/tools/go/ssa.(*Package).Build(...)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/ssa/builder.go:2413
golang.org/x/tools/go/analysis/passes/buildssa.run(0xc00156cf70)
        /home/runner/go/pkg/mod/golang.org/x/[email protected]/go/analysis/passes/buildssa/buildssa.go:73 +0x1a8
github.com/praetorian-inc/gokart/run.RunAnalyzers({0x1075c00, 0x5, 0x0?}, 0xc0005bbc80)
        /home/runner/work/gokart/gokart/run/run.go:133 +0x1cf
github.com/praetorian-inc/gokart/run.Run({0x1075c00, 0x5, 0x5}, {0xc000189120?, 0x0?, 0x0?})
        /home/runner/work/gokart/gokart/run/run.go:42 +0x11e
github.com/praetorian-inc/gokart/analyzers.Scan({0xc000189120?, 0x1, 0x1})
        /home/runner/work/gokart/gokart/analyzers/scan.go:163 +0x5d8
github.com/praetorian-inc/gokart/cmd.glob..func1(0x107d200?, {0xc000189120, 0x1, 0x1})
        /home/runner/work/gokart/gokart/cmd/scan.go:91 +0x42d
github.com/spf13/cobra.(*Command).execute(0x107d200, {0xc0001890f0, 0x1, 0x1})
        /home/runner/go/pkg/mod/github.com/spf13/[email protected]/command.go:860 +0x663
github.com/spf13/cobra.(*Command).ExecuteC(0x107cf80)
        /home/runner/go/pkg/mod/github.com/spf13/[email protected]/command.go:974 +0x3bd
github.com/spf13/cobra.(*Command).Execute(...)
        /home/runner/go/pkg/mod/github.com/spf13/[email protected]/command.go:902
github.com/praetorian-inc/gokart/cmd.Execute(...)
        /home/runner/work/gokart/gokart/cmd/root.go:61
main.main()
        /home/runner/work/gokart/gokart/main.go:38 +0x25

custom Taint tracking/data flow rule

After reading the readme doc, I'm wondering that how to config a custom taint tracking or data flow analysis.
For example, I hope to config some "source pattern" and "sink pattern", then the gokart can tell me the the path from source to sink.

Error messages are printed to stdout

When GoKart runs into non-fatal errors, like with unloadable packages (see #56), error messages are emitted to stdout. This causes problems if using GoKart's JSON or SARIF output modes, as then GoKart emits badly-formed documents to stdout.

Error messages should probably instead be printed to stderr.

Comparism with CodeQL

Would it be possible to compare gokart with CodeQL, at least on some ballpark figure? For instance, can gokart detect problems with int conversions between different sizes, et cetera? For instance, CodeQL is very helpful at catching such things.

And finally, the obvious question: does gokart detect race conditions?

Error message for unloadable packages is inactionable

When GoKart scans a project, if dependencies fail to load, an error message is emitted. But the message is sparse on details, and doesn't give any clue as to what went wrong.

For example, when looking at go-algorand using gokart commit bb678c0 and go version go1.17.1 darwin/amd64, I get this:

gokart scan -v
Using config found at /Users/blarsen/.gokart/analyzers.yml

Revving engines VRMMM VRMMM
3...2...1...Go!

Uh oh, a dashboard light is on! GoKart was unable to load the following packages:
- "github.com/algorand/go-algorand/crypto"
- "github.com/algorand/go-algorand/data/committee/sortition"

...

Why did those packages fail to load? Are there more details that GoKart is omitting?

Output clean-ups - Issues are reported multiple times.

Hi!

Thanks for developing this awesome project. I was experimenting it today, and found an odd bug. When scanning Golang apps with finding.

  1. Source code line content is not shown on SARIF.

  2. When scanning vulnerable golang apps (https://github.com/0c34/govwa), there are findings on default and JSON format, and one finding on SARIF.

  3. Reporting on JSON is a bit hard to follow; it may need to be standardized into a single-document format instead of the current one. The JSON report has multiple JSON objects, one per each line, and then an invalid text (string). I also find that the findings are repeated. It may need to be reviewed.

  4. Untrusted sources are not shown on SARIF. It can be found on JSON output, but it's not there on SARIF.

panic: err: go command required

If go is not installed scan panics. Not a usual scenario.

alexandre@localhost:~> gokart scan
Using default analyzers config found at "~/.gokart/analyzers.yml".
No existing analyzers.yml file found - writing default to ~/.gokart/analyzers.yml

Revving engines VRMMM VRMMM
3...2...1...Go!
panic: err: go command required, not found: exec: "go": executable file not found in $PATH: stderr: 

goroutine 1 [running]:
github.com/praetorian-inc/gokart/analyzers.Scan(0xc000035f80, 0x1, 0x1)
	/home/abuild/rpmbuild/BUILD/gokart-0.1.0/analyzers/scan.go:97 +0x135f
github.com/praetorian-inc/gokart/cmd.glob..func1(0x55a77c40cc20, 0xc000035f80, 0x1, 0x1)
	/home/abuild/rpmbuild/BUILD/gokart-0.1.0/cmd/scan.go:53 +0x1ca
github.com/spf13/cobra.(*Command).execute(0x55a77c40cc20, 0x55a77c43fa00, 0x0, 0x0, 0x55a77c40cc20, 0x55a77c43fa00)
	/home/abuild/rpmbuild/BUILD/gokart-0.1.0/vendor/github.com/spf13/cobra/command.go:860 +0x2c2
github.com/spf13/cobra.(*Command).ExecuteC(0x55a77c40c9a0, 0xc000000180, 0xc00013bf78, 0x55a77bb9efc5)
	/home/abuild/rpmbuild/BUILD/gokart-0.1.0/vendor/github.com/spf13/cobra/command.go:974 +0x375
github.com/spf13/cobra.(*Command).Execute(...)
	/home/abuild/rpmbuild/BUILD/gokart-0.1.0/vendor/github.com/spf13/cobra/command.go:902
github.com/praetorian-inc/gokart/cmd.Execute(...)
	/home/abuild/rpmbuild/BUILD/gokart-0.1.0/cmd/root.go:61
main.main()
	/home/abuild/rpmbuild/BUILD/gokart-0.1.0/main.go:38 +0x34

Perhaps log.Fatal would make more sense in here as the analysis failed for some reason, I don't think anyone is going to recover from here.

Support Generic Issue Format

Some tools (gosec for example) support Generic Issue Format which allows exporting found issues into SonarQube. It would be a cool feature to support this format

multi analyzers in analyzers.yml cause error

first i add some analyzers in yml
image
then, i add some debug code in generic.go

func genericFunctionRun(pass *analysis.Pass, vulnPathFuncs map[string][]string,
	name string, message string) (interface{}, error) {
	fmt.Println(name, message) <- add debug code
        ...

run gokart to scan a test project, and this project only has two files: go.mod, main.go

gokart scan -i /foo/bar/analyzers.yml /foo/testproject/

expect output:

Revving engines VRMMM VRMMM
3...2...1...Go!
Test Sink1 test1
Test Sink2 test2

actual output:

Revving engines VRMMM VRMMM
3...2...1...Go!
Test Sink2 test2
Test Sink2 test2

Add more Sinks to Command Injection analyzer

A review of some other ways to perform command execution in Go has yielded these additional sinks which should have high to noise ratio and should be included directly into the analyzer.

  • syscall/Exec()
  • syscall/ForkExec()
  • syscall/StartProcess()
  • golang.org/x/sys/execabs/Command()
  • golang.org/x/sys/execabs/CommandContext()

Analyzers do not set ResultType

According to https://pkg.go.dev/golang.org/x/tools/go/analysis#Analyzer:

type Analyzer struct {
	// ...

	// Run applies the analyzer to a package.
	// It returns an error if the analyzer failed.
	//
	// On success, the Run function may return a result
	// computed by the Analyzer; its type must match ResultType.
	// The driver makes this result available as an input to
	// another Analyzer that depends directly on this one (see
	// Requires) when it analyzes the same package.
	//
	// To pass analysis results between packages (and thus
	// potentially between address spaces), use Facts, which are
	// serializable.
	Run func(*[Pass](https://pkg.go.dev/golang.org/x/tools/go/analysis#Pass)) (interface{}, [error](https://pkg.go.dev/builtin#error))

	// ...

	// ResultType is the type of the optional result of the Run function.
	ResultType [reflect](https://pkg.go.dev/reflect).[Type](https://pkg.go.dev/reflect#Type)

	// ...
}

Because of this, the analyzers fail to run:

analyzer "command_injection" failed: internal error: on package github.com/jcmturner/gokrb5/v8/iana, analyzer command_injection returned a result of type []util.Finding, but declared ResultType <nil>

detect when external command running is vulnerable to option injection

I noticed that gokart supports checking for command injection. Another related thing is when injecting command-line parameters allows you to inject parameters that get interpreted as options. Some options change the behaviour of commands in suboptimal ways, but some options to some commands can result in arbitrary code execution. The canonical paper about this type of attack is Back To The Future: Unix Wildcards Gone Wild by Leon Juranic of DefenseCode. It would be great if gokart could support detecting option injection.

Add version command to gokart

Current gokart doesn't show its version now and it's not possible check in CI or on local machine that gokart is not outdated.

Scan reports scanning varying number of files

On the same repository, with no code changes, gokart reports scanning a varying number of files. Is this normal behavior, if so can you explain why? Thanks.

To Reproduce

# fresh clone of gokart
git clone [email protected]:praetorian-inc/gokart.git /tmp/gokart

# change to gokart directory
cd /tmp/gokart

# scan a bunch, comparing files scanned
function scan {
    for i in {1..25}; do
       go run main.go scan . | grep "Go files were scanned" | cut -f 7 -d ' '
    done
}
scan | sort | uniq -c | sort -rn

Output

12 504
 7 505
 2 503
 2 499
 1 500
 1 498

Editor-friendly output format

This tool currently outputs both verbose and useless information directly into
stdout, which makes using this in an automated fashion seem very hard:

―❤―▶ gokart scan . 2> /dev/null
Using default analyzers config found at "~/.gokart/analyzers.yml".

Revving engines VRMMM VRMMM
3...2...1...Go!

Uh oh, a dashboard light is on! GoKart was unable to load the following packages: 
- "github.com/diamondburned/gotktrix/internal/app/emojiview"
- "github.com/diamondburned/gotktrix/cmd/emoji-uploader"

Race Complete! Analysis took 3.254922703s and 1261 Go files were scanned (including imported packages)
GoKart found 0 potentially vulnerable functions

I think it would be better for there to be a flag that makes gokart output
only the information that the user actually cares about, similar to staticcheck:

―❤―▶ staticcheck ./...
internal/gotktrix/internal/db/node.go:74:6: func convertPrefix is unused (U1000)
internal/gotktrix/internal/db/node.go:78:6: func appendString is unused (U1000)
internal/secret/secret.go:12:5: var drivers is unused (U1000)

With staticcheck's format, I should be able to trivially add this tool into
Vim.

Docker image size

Size image from main branch: 454MB

Image size this branch: 23.5MB

Generics support

When I scan a repo using Go 1.18 generics, gokart panics with the message: zeroConst: unexpected T.

For reference, the only function in the repo using generics is as follows:

func mapSlice[T any, M any](a []T, f func(T) M) []M {
	n := make([]M, len(a))
	for i, e := range a {
		n[i] = f(e)
	}
	return n
}

It looks like x/tools/go/ssa is still waiting on generics support. I'm raising this here as a reference and reminder to check that analysis of generics works once that package is fixed.

Support to gokart in github actions marketplace

hey hey do you have any plans to create a gokart action for us to use in github actions?

I'm testing the gokart, I'm finding it really cool and I'd like to add it to github actions for an action very similar to gosec because of this the my question

thanks 😊

Implement support for non-nil exit code

Hi!

To ease the use of this tool in automated systems such as CI/CD, and enable an optional failure mode on possible vulnerability findings, I suggest to implement a new boolean argument such as in #9 .

With a non-nil exit code the CI/CD can stop pipelines and jobs easily when a potential vulnerability is found.

RSA warnings are suppressed in output

Result

Race Complete! Analysis took 84.813012ms and 24 Go files were scanned (including imported packages)
GoKart found 0 potentially vulnerable functions

Expected

(CWE-326: Inadequate Encryption Strength) Danger: RSA key length is too short, recommend 2048

To Reproduce

# create temporary directory
mkdir -p /tmp/rsa

# create minimal go file also at (https://play.golang.com/p/1Js9F91OGDk.go)
cat > /tmp/rsa/main.go <<-"EOF"
package main

import (
        "crypto/rand"
        "crypto/rsa"
)

func main() {
        rsa.GenerateKey(rand.Reader, 100)
}
EOF

# make module so gokart runs in directory
cat > /tmp/rsa/go.mod <<-EOF
module demo.thing/rsa

go 1.19
EOF

# scan with gokart
gokart scan /tmp/rsa/

Exploration

Since

results = append(results, util.MakeFinding(message, targetFunc, nil, "CWE-326: Inadequate Encryption Strength"))
is always passing nil as the untrusted_source, and
if len(finding.Untrusted_Source) == 0 {
is always considering 0 length Untrusted_Source's to be an invalid finding, the actual notice gets filterred out.

There are no unit tests for util/finding.go or integration tests for analyzers/scan.go, so this is missed (since the tests in analyzers/scan.go only test that the returned results contains the expected number of results, not the correct number of "ValidFindings").

Workaround

I found that by adding []util.TaintedCode{{SourceCode: vulnFunc.Instr.Call.Value.String()}} to the result, that gokart prints it. It doesn't feel entirely correct since it's not necessarily "Untrusted Input", but at least it is bringing attention to it (hence the workaround, not actual fix).

New Output

(CWE-326: Inadequate Encryption Strength) Danger: RSA key length is too short, recommend 2048

/tmp/rsa/main.go:9
Vulnerable Function: [ main(...) ]
      8:	func main() {
    > 9:	        rsa.GenerateKey(rand.Reader, 100)
      10:	}

:0
Source of Untrusted Input: [ (...) ]
      -1:	
    > 0:	crypto/rsa.GenerateKey
      1:	
------------------------------------------------------------------------------

Race Complete! Analysis took 81.617933ms and 24 Go files were scanned (including imported packages)
GoKart found 1 potentially vulnerable functions
Identified 1 potential CWE-326: Inadequate Encryption Strength

Patch

-results = append(results, util.MakeFinding(message, targetFunc, nil, "CWE-326: Inadequate Encryption Strength"))
+results = append(results, util.MakeFinding(message, targetFunc, []util.TaintedCode{{SourceCode: vulnFunc.Instr.Call.Value.String()}}, "CWE-326: Inadequate Encryption Strength"))

False positives for SSRF

Finding gokart really useful so far: nice work!

Using 0.1.0, I see quite a lot of false positives for SSRF. For example,

package bug

import "net/http"

func doSomething(req *http.Request) (*http.Response, error) {
	return http.DefaultClient.Do(req)
}

func DoSomething() (*http.Response, error) {
	req, err := http.NewRequest("GET", "http://example.com", nil)
	if err != nil {
		return nil, err
	}
	return doSomething(req)
}
$ gokart scan
Using default analyzers config found at "~/.gokart/analyzers.yml".

Revving engines VRMMM VRMMM
3...2...1...Go!

(SSRF) Danger: possible SSRF detected

/home/stevie/gokart/bug.go:6
Vulnerable Function: [ doSomething(...) (*net/http.Response, error ]
      5:	func doSomething(req *http.Request) (*http.Response, error) {
    > 6:		return http.DefaultClient.Do(req)
      7:	}

/home/stevie/gokart/bug.go:5
Source of Untrusted Input: [ doSomething(...) (*net/http.Response, error ]
      4:	
    > 5:	func doSomething(req *http.Request) (*http.Response, error) {
      6:		return http.DefaultClient.Do(req)
------------------------------------------------------------------------------

Race Complete! Analysis took 417.122169ms and 81 Go files were scanned (including imported packages)
GoKart found 1 potentially vulnerable functions

It looks like any function which takes an *http.Request as an argument and passes it to Do will be flagged as potentially vulnerable? In the above example, the request url comes from a string literal so isn't tainted.

Include count by type in output

As a security analyst reviewing open source Go libraries used across an enterprise, it would be helpful to to augment the current output:

GoKart found N potentially vulnerable functions

with the number of Command Injection, Path Traversal & SSRF found.

Currently, I have to grep for it and would like to further automate the process.

Outputting results to SARIF file also records stdout messages

Was trying to use SARIF files written by gokart, but noticed when they identify issues, it seems to record some messages that seem destined for stdout.

Here's an example:

This is the command I ran: gokart scan -s -o results.sarif .
The raw file output is listed below, notice that the last line is:

Identified 2 potential CWE-78: OS Command Injection

It isn't present when there are no identified issues.

{
  "version": "2.1.0",
  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
  "runs": [
    {
      "tool": {
        "driver": {
          "name": "GoKart",
          "informationUri": "https://github.com/praetorian-inc/gokart"
        }
      },
      "results": [
        {
          "ruleId": "CWE-78: OS Command Injection",
          "message": {
            "text": "Danger: possible command injection detected"
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "REDACTED"
                },
                "region": {
                  "startLine": 22,
                  "endLine": 22
                }
              }
            }
          ]
        },
        {
          "ruleId": "CWE-78: OS Command Injection",
          "message": {
            "text": "Danger: possible command injection detected"
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "REDACTED"
                },
                "region": {
                  "startLine": 44,
                  "endLine": 44
                }
              }
            }
          ]
        }
      ]
    }
  ]
}
Identified 2 potential CWE-78: OS Command Injection

Channel incorrectly identified as source of untrusted input

Using v0.1.0 with the following program:

package main

import (
	"io/ioutil"
	"os"
	"os/signal"
	"syscall"
)

func output(filename string) {
	ioutil.WriteFile(filename, []byte("foo"), 0644)
}

func main() {
	filename := "foo" // not attacker controlled
	sigs := make(chan os.Signal, 1)
	done := make(chan bool)
	signal.Notify(sigs, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

	go func() {
		<-sigs
		done <- true
	}()
	go func() {
		<-done
		output(filename)
	}()
	output(filename)

}
$ gokart scan
Using default analyzers config found at "~/.gokart/analyzers.yml".

Revving engines VRMMM VRMMM
3...2...1...Go!

(Path Traversal) Danger: possible path traversal injection detected

/home/stevie/gokart/foo.go:11
Vulnerable Function: [ output(...) ]
      10:	func output(filename string) {
    > 11:		ioutil.WriteFile(filename, []byte("foo"), 0644)
      12:	}

/home/stevie/gokart/foo.go:17
Source of Untrusted Input: [ output(...) ]
      16:		sigs := make(chan os.Signal, 1)
    > 17:		done := make(chan bool)
      18:		signal.Notify(sigs, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
------------------------------------------------------------------------------

Race Complete! Analysis took 177.741198ms and 72 Go files were scanned (including imported packages)
GoKart found 1 potentially vulnerable functions

Note that the channel done is identified as an untrusted input. If I remove the call to output from the goroutine

@@ -23,7 +23,6 @@
 	}()
 	go func() {
 		<-done
-		output(filename)
 	}()
 	output(filename)

the scan (correctly) finds no problems:

$ gokart scan
Using default analyzers config found at "~/.gokart/analyzers.yml".

Revving engines VRMMM VRMMM
3...2...1...Go!

Race Complete! Analysis took 203.734926ms and 72 Go files were scanned (including imported packages)
GoKart found 0 potentially vulnerable functions

Verbose trace has incorrect parent signatures

While trying to trace data thru a multiple file trace, it becomes clear that the parent function signature pertains to the parent function of the sink, rather than the source.

/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/promMetricFetcher.go:55
Vulnerable Function: [ getMetric(...) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error ]
      54:		httpClient := http.Client{}
    > 55:		resp, err := httpClient.Do(req /*req.WithContext(ctx)*/)
      56:		if err != nil {

/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/roundpoller.go:39
Source of Untrusted Input: [ getMetric(...) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error ]
      38:		reader := bufio.NewReader(file)
    > 39:		line, _, _ := reader.ReadLine()
      40:	
�[32m
############################### FULL TRACE ###############################
�[0m
Untrusted Input Source:/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/roundpoller.go:39:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	line, _, _ := reader.ReadLine()
/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/roundpoller.go:30:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	func readHostFile(telemetryHostFile string) (bytes []byte, err error) {
/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/puppeteer.go:440:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	hostNameBytes, err := readHostFile(telemetryHostFile)
/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/puppeteer.go:444:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	metricFetcher := makePromMetricFetcher(string(hostNameBytes))
/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/promMetricFetcher.go:37:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	func makePromMetricFetcher(host string) *promMetricFetcher {
/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/promMetricFetcher.go:44:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	func (r *promMetricFetcher) getMetric(query string) (results []promValueResult, err error) {
/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/promMetricFetcher.go:45:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	queryURL := fmt.Sprintf("http://%s:9090/api/v1/query", r.promHost)
/Users/ianspiro/Documents/sandbox/chariot-2021/test-track/go-algorand/test/netperf-go/puppeteer/promMetricFetcher.go:46:
[ getMetric (query string) (results []github.com/algorand/go-algorand/test/netperf-go/puppeteer.promValueResult, err error) ]
>>>	req, err := http.NewRequest("GET", queryURL, nil)

Use to ko build containers

Use ko to build docker images. ko https://github.com/google/ko by default uses distroless images.

Motivation for moving to distroless images.

Rebasing the k8s images to distroless/static can make the images thinner, safer and less vulnerable.
https://github.com/kubernetes/enhancements/blob/master/keps/sig-release/1729-rebase-images-to-distroless/README.md#motivation

The containers are not signed.
The distroless images are signed. https://github.com/GoogleContainerTools/distroless#how-do-i-verify-distroless-images

docker trust inspect --pretty golang:1.16-alpine

No signatures for golang:1.16-alpine


Administrative keys for golang:1.16-alpine

  Repository Key:	fb57d64910e2f7fa4456e938c547398305f26c15c76e9de89f76e4f32e1fd0bc
  Root Key:	c6b86f21ae272f3ae27b8da8a5762df97f09d6d0604ab49dd1d9920c6e25b65b

FROM golang:1.16-alpine

Feature request: integrate gokart in golangci-lint

We use golangci-lint to unify the linters that we run against our Go codebase. Some of the benefits is that it is faster than running the tools independently, and the output format is consistent, allowing us to pass the results to further tools such as Sonar. An other advantage for the gokart project is that it would increase exposure to it as golangci-lint has decent following.

This is the project page for golangci-lint:

GoKart panics in the `TaintAnalyzer`

When scanning a project, GoKart panics with the following trace when running the TaintAnalyzer:

gokart scan
Using config found at /home/smoyer1/.gokart/analyzers.yml

Revving engines VRMMM VRMMM
3...2...1...Go!
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x9ebf55]

goroutine 1 [running]:
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc00235c210, 0x3?, 0xa, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:175 +0x3f5
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc00646a2e0, 0x0?, 0x9, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:200 +0x267b
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc00235cc10, 0x0?, 0x8, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:171 +0x1105
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc003cd81d0, 0xb70b90?, 0x7, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:163 +0x1816
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc006396d10, 0x0?, 0x6, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:141 +0x1fb2
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc0063b0e58, 0x0?, 0x5, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:232 +0x8b3
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc00235e030, 0x0?, 0x4, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:270 +0x1de9
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc00235e580, 0x3?, 0x3, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:212 +0x4ec
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc00235ea90, 0x4?, 0x2, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:200 +0x267b
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc0063c0460, 0x0?, 0x1, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:200 +0x267b
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaintRecurse(0xc00235f3f8, 0xc0063c4140, 0xc0063c60b0, 0x15?, 0x0, {0xc00235f2d8?, 0x0, 0x0})
        /home/smoyer1/git/gokart/util/taint.go:171 +0x1105
github.com/praetorian-inc/gokart/util.(*TaintAnalyzer).ContainsTaint(...)
        /home/smoyer1/git/gokart/util/taint.go:62
github.com/praetorian-inc/gokart/analyzers.ssrfRun(0xc0066043c0)
        /home/smoyer1/git/gokart/analyzers/ssrf.go:157 +0x6d5
github.com/praetorian-inc/gokart/run.RunAnalyzers({0x1088f00, 0x5, 0xb70eab?}, 0xc000b95c80)
        /home/smoyer1/git/gokart/run/run.go:173 +0x502
github.com/praetorian-inc/gokart/run.Run({0x1088f00, 0x5, 0x5}, {0xc00019b9c0?, 0x0?, 0x0?})
        /home/smoyer1/git/gokart/run/run.go:42 +0x11e
github.com/praetorian-inc/gokart/analyzers.Scan({0xc00019b9c0?, 0x1, 0x1})
        /home/smoyer1/git/gokart/analyzers/scan.go:163 +0x5d8
github.com/praetorian-inc/gokart/cmd.glob..func1(0x1090500?, {0x10c87a8, 0x0, 0x0})
        /home/smoyer1/git/gokart/cmd/scan.go:91 +0x42d
github.com/spf13/cobra.(*Command).execute(0x1090500, {0x10c87a8, 0x0, 0x0})
        /home/smoyer1/go/pkg/mod/github.com/spf13/[email protected]/command.go:860 +0x663
github.com/spf13/cobra.(*Command).ExecuteC(0x1090280)
        /home/smoyer1/go/pkg/mod/github.com/spf13/[email protected]/command.go:974 +0x3bd
github.com/spf13/cobra.(*Command).Execute(...)
        /home/smoyer1/go/pkg/mod/github.com/spf13/[email protected]/command.go:902
github.com/praetorian-inc/gokart/cmd.Execute(...)
        /home/smoyer1/git/gokart/cmd/root.go:61
main.main()
        /home/smoyer1/git/gokart/main.go:38 +0x25

This occurs because the Pkg field of a function might be nil according to the code's comments, but no nil check is included:

https://github.com/golang/tools/blob/b01e7a4e75d3f07db097384f829839c6628a46c8/go/ssa/ssa.go#L306-L317

As an aside, the project producing this panic includes generics which might be related or at least sympathetic. If so, it's related to #72. Feel free to assign this to me as I've got both this issue and #72 fixed and running as expected against a project that contains generics.

panic: no concrete method, gokart 0.5.1, go 1.21

Using config found at ...\.gokart\analyzers.yml

Revving engines VRMMM VRMMM
3...2...1...Go!
panic: no concrete method: func (*math/rand.Rand).ExpFloat64() float64

goroutine 1 [running]:
golang.org/x/tools/go/ssa.(*Program).declaredFunc(0xc000000d80, 0xc001911ce0)
...
$ gokart version
v0.5.1

$ go version
go version go1.21.0 windows/amd64

panic: index out of range

OS: macOS Big Sur (11.5.1)
GoKart Version: 0.1.0
Config: default
Target: github.com/spiffe/spire

Decided to give this a whirl against github.com/spiffe/spire but unfortunately hit a panic.

$ go install github.com/praetorian-inc/gokart@latest
go: downloading github.com/praetorian-inc/gokart v0.1.0
go: downloading github.com/lithammer/dedent v1.1.0
go: downloading github.com/owenrumney/go-sarif v1.0.11
go: downloading github.com/segmentio/fasthash v1.0.3
go: downloading golang.org/x/tools v0.1.2
go: downloading github.com/zclconf/go-cty v1.8.4
$ git clone https://github.com/spiffe/spire
$ cd spire
$ gokart scan .
Using default analyzers config found at "~/.gokart/analyzers.yml".
No existing analyzers.yml file found - writing default to ~/.gokart/analyzers.yml

Revving engines VRMMM VRMMM
3...2...1...Go!
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/praetorian-inc/gokart/util.OutputFinding(0xc001acaf60, 0x2f, 0xc005a53e80, 0x7a, 0xc00205b680, 0x4a, 0x48, 0xc001acaf90, 0x28, 0x0, ...)
	/redacted/go/pkg/mod/github.com/praetorian-inc/[email protected]/util/finding.go:54 +0x116f
github.com/praetorian-inc/gokart/analyzers.Scan(0xc000074330, 0x1, 0x1)
	/redacted/go/pkg/mod/github.com/praetorian-inc/[email protected]/analyzers/scan.go:128 +0x5bd
github.com/praetorian-inc/gokart/cmd.glob..func1(0x16dcd00, 0xc000074330, 0x1, 0x1)
	/redacted/go/pkg/mod/github.com/praetorian-inc/[email protected]/cmd/scan.go:53 +0x1ca
github.com/spf13/cobra.(*Command).execute(0x16dcd00, 0xc000074300, 0x1, 0x1, 0x16dcd00, 0xc000074300)
	/redacted/go/pkg/mod/github.com/spf13/[email protected]/command.go:860 +0x2c2
github.com/spf13/cobra.(*Command).ExecuteC(0x16dca80, 0xc000000180, 0xc00016df78, 0x1006a25)
	/redacted/go/pkg/mod/github.com/spf13/[email protected]/command.go:974 +0x375
github.com/spf13/cobra.(*Command).Execute(...)
	/redacted/go/pkg/mod/github.com/spf13/[email protected]/command.go:902
github.com/praetorian-inc/gokart/cmd.Execute(...)
	/redacted/go/pkg/mod/github.com/praetorian-inc/[email protected]/cmd/root.go:61
main.main()
	/redacted/go/pkg/mod/github.com/praetorian-inc/[email protected]/main.go:38 +0x32

Scan command doesn't pick up all packages

gokart scan does not pick up all packages when run from within a top-level folder

Expected behavior: scan command finds and scans all modules defined in a go.mod file
Actual behavior: scan | scan . | scan ./... all produce findings for only the top level module defined in go.mod file

gokart scan 
Race Complete! Analysis took 2.976379315s and 798 Go files were scanned (including imported packages)
GoKart found 3 potentially vulnerable functions
#using * as directory argument recurses through all packages
gokart scan *
Race Complete! Analysis took 6.974210601s and 1734 Go files were scanned (including imported packages)
GoKart found 29 potentially vulnerable functions

Steps to reproduce:

git clone https://github.com/isp1r0/mongo-go-driver/
cd mongo-go-driver
gokart scan

False positive path traversal with unrelated untrusted input indicated

Version 0.1.0.

package foo

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
)

func output(name string) error {
	f, err := os.Open(name)
	if err != nil {
		return err
	}
	f.Write([]byte("foo"))
	defer f.Close()

	g, err := os.OpenFile("foo", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
	if err != nil {
		return err
	}
	g.Write([]byte("foo"))
	return g.Close()
}

func Foo() (err error) {
	tmpdir, err := ioutil.TempDir("", "foo")
	if err != nil {
		return err
	}
	defer func() {
		if rerr := os.RemoveAll(tmpdir); rerr != nil {
			log.Println(err)
			err = rerr
			return
		}
	}()

	filename := filepath.Join(tmpdir, "foo.tmp")

	return output(filename)
}

gives output

$ gokart scan
Using default analyzers config found at "~/.gokart/analyzers.yml".

Revving engines VRMMM VRMMM
3...2...1...Go!

(Path Traversal) Danger: possible path traversal injection detected

/home/stevie/gokart/foo.go:11
Vulnerable Function: [ output(...) error ]
      10:	func output(name string) error {
    > 11:		f, err := os.Open(name)
      12:		if err != nil {

/home/stevie/gokart/foo.go:18
Source of Untrusted Input: [ output(...) error ]
      17:	
    > 18:		g, err := os.OpenFile("foo", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
      19:		if err != nil {
------------------------------------------------------------------------------

Race Complete! Analysis took 146.430242ms and 63 Go files were scanned (including imported packages)
GoKart found 1 potentially vulnerable functions

Clearly, the line flagged as untrusted input is unrelated to name. If I remove the defer statement from Foo, no path traversal issue is detected.

Publish gokart in docker github packages

do you think it makes sense to post a gokart docker image in github packages? I really like the idea of ​​this type of tool that I can use docker run praetorian-inc/gokart scan ...

I even have something very similar here https://github.com/renanpalmeira/docker-protobufs/pkgs/container/protobuf

on a daily basis I end up using it like this:

docker run --rm \
    --name my-protos \
    -u $(id -u):$(id -u) \
    -v `pwd`:/code \
    ghcr.io/renanpalmeira/protobuf:latest \
        --proto_path=/code/protos \
        --go_out=plugins=grpc,paths=source_relative:/code/protos/gen \
        /code/protos/*.proto

Add command line flag to write out findings to file

As a developer looking to add GoKart into my CI/CD pipeline integration, I need a way to output findings to a file.

Proposed solution: Adding a new command line flag: -o, -output

Details:

  • Flag should take an optional argument of for text file to write to
  • If optional argument is missing, default to a reasonable, unique name
  • Redirect console output to file to preserve other flag functionality

Alternatives to consider:

  • Write out findings in a standard json format rather than directly to a text file, limiting the scope to the standard 'scan' output
  • Require a user provided argument, alleviating the need for default naming logic

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.