Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/ci-rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ jobs:
fileName: opentaint-project-analyzer.jar
out-file-path: opentaint-analyzer

- uses: robinraju/release-downloader@v1.12
with:
repository: ${{ github.repository }}
token: ${{ secrets.SEQRA_GITHUB_TOKEN }}
tag: go-server/latest
fileName: go-ssa-server_linux_amd64
out-file-path: opentaint-go-server

- name: Mark go-ssa-server executable
run: chmod +x opentaint-go-server/go-ssa-server_linux_amd64

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
Expand All @@ -61,6 +72,11 @@ jobs:
SEQRA_GITHUB_ACTOR: ${{ secrets.SEQRA_GITHUB_ACTOR }}
SEQRA_GITHUB_TOKEN: ${{ secrets.SEQRA_GITHUB_TOKEN }}

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25.x'

- name: OpenTaint compile test project
run: |
java -jar opentaint-autobuilder/opentaint-project-auto-builder.jar \
Expand All @@ -71,6 +87,8 @@ jobs:
--verbosity debug

- name: Run OpenTaint analyzer
env:
GOIR_SERVER_BINARY: opentaint-go-server/go-ssa-server_linux_amd64
run: |
java -Xmx8G -Djdk.util.jar.enableMultiRelease=false -Dorg.opentaint.ir.impl.storage.defaultBatchSize=2000 \
-jar opentaint-analyzer/opentaint-project-analyzer.jar \
Expand Down
20 changes: 20 additions & 0 deletions rules/ruleset/go/lib/go-cmdi-sinks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
rules:
- id: go-cmdi-sinks
options: {lib: true}
languages: [go]
severity: ERROR
message: OS command execution sink
mode: taint
pattern-sinks:
- pattern-either:
- pattern: exec.Command($NAME, ...)
- pattern: exec.CommandContext($CTX, $NAME, ...)
- pattern: exec.LookPath($NAME)
- pattern: os.StartProcess($NAME, ...)
- pattern: syscall.Exec($NAME, ...)
- pattern: syscall.ForkExec($NAME, ...)
- pattern: syscall.StartProcess($NAME, ...)
- pattern: "($C : *exec.Cmd).CombinedOutput()"
- pattern: "($C : *exec.Cmd).Run()"
- pattern: "($C : *exec.Cmd).Output()"
- pattern: "($C : *exec.Cmd).Start()"
40 changes: 40 additions & 0 deletions rules/ruleset/go/lib/go-path-sinks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
rules:
- id: go-path-sinks
options: {lib: true}
languages: [go]
severity: ERROR
message: Filesystem path sink
mode: taint
pattern-sinks:
- pattern-either:
- pattern: os.Open($P)
- pattern: os.OpenFile($P, ...)
- pattern: os.Create($P)
- pattern: os.CreateTemp($DIR, $PAT)
- pattern: os.MkdirTemp($DIR, $PAT)
- pattern: os.Mkdir($P, ...)
- pattern: os.MkdirAll($P, ...)
- pattern: os.Remove($P)
- pattern: os.RemoveAll($P)
- pattern: os.ReadFile($P)
- pattern: os.WriteFile($P, ...)
- pattern: os.ReadDir($P)
- pattern: os.Stat($P)
- pattern: os.Lstat($P)
- pattern: os.Truncate($P, ...)
- pattern: os.Chdir($P)
- pattern: os.Chmod($P, ...)
- pattern: os.Chown($P, ...)
- pattern: os.Lchown($P, ...)
- pattern: os.Chtimes($P, ...)
- pattern: os.Readlink($P)
- pattern: os.Rename($A, $B)
- pattern: os.Link($A, $B)
- pattern: os.Symlink($A, $B)
- pattern: os.DirFS($P)
- pattern: ioutil.ReadFile($P)
- pattern: ioutil.WriteFile($P, ...)
- pattern: ioutil.ReadDir($P)
- pattern: ioutil.TempFile($DIR, $PAT)
- pattern: ioutil.TempDir($DIR, $PAT)
- pattern: http.ServeFile($W, $R, $P)
32 changes: 32 additions & 0 deletions rules/ruleset/go/lib/go-sql-sinks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
rules:
- id: go-sql-sinks
options: {lib: true}
languages: [go]
severity: ERROR
message: SQL query execution sink
mode: taint
pattern-sinks:
- patterns:
- pattern: "($DB : *sql.DB).Query($SQL, ...)"
- focus-metavariable: $SQL
- patterns:
- pattern: "($DB : *sql.DB).QueryContext($CTX, $SQL, ...)"
- focus-metavariable: $SQL
- patterns:
- pattern: "($DB : *sql.DB).QueryRow($SQL, ...)"
- focus-metavariable: $SQL
- patterns:
- pattern: "($DB : *sql.DB).QueryRowContext($CTX, $SQL, ...)"
- focus-metavariable: $SQL
- patterns:
- pattern: "($DB : *sql.DB).Exec($SQL, ...)"
- focus-metavariable: $SQL
- patterns:
- pattern: "($DB : *sql.DB).ExecContext($CTX, $SQL, ...)"
- focus-metavariable: $SQL
- patterns:
- pattern: "($DB : *sql.DB).Prepare($SQL)"
- focus-metavariable: $SQL
- patterns:
- pattern: "($DB : *sql.DB).PrepareContext($CTX, $SQL)"
- focus-metavariable: $SQL
21 changes: 21 additions & 0 deletions rules/ruleset/go/lib/go-ssrf-sinks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
rules:
- id: go-ssrf-sinks
options: {lib: true}
languages: [go]
severity: ERROR
message: Outbound HTTP request sink
mode: taint
pattern-sinks:
- patterns:
- pattern-either:
- pattern: http.Get($U)
- pattern: http.Head($U)
- pattern: http.Post($U, ...)
- pattern: http.PostForm($U, ...)
- pattern: "($C : *http.Client).Get($U)"
- pattern: "($C : *http.Client).Head($U)"
- pattern: "($C : *http.Client).Post($U, ...)"
- pattern: "($C : *http.Client).PostForm($U, ...)"
- pattern: http.NewRequest($M, $U, ...)
- pattern: http.NewRequestWithContext($CTX, $M, $U, ...)
- focus-metavariable: $U
16 changes: 16 additions & 0 deletions rules/ruleset/go/lib/go-ssti-sinks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
rules:
- id: go-ssti-sinks
options: {lib: true}
languages: [go]
severity: ERROR
message: Template source parse sink
mode: taint
pattern-sinks:
- patterns:
- pattern-either:
- pattern: template.New($N).Parse($SRC)
- pattern: template.Must(template.New($N).Parse($SRC))
- pattern: "($T : *template.Template).Parse($SRC)"
- pattern: template.New($N).ParseFiles($SRC, ...)
- pattern: template.New($N).ParseGlob($SRC)
- focus-metavariable: $SRC
27 changes: 27 additions & 0 deletions rules/ruleset/go/lib/go-xss-sinks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
rules:
- id: go-xss-sinks
options: {lib: true}
languages: [go]
severity: ERROR
message: HTTP response write sink
mode: taint
pattern-sinks:
- pattern-either:
- pattern: $W.Write($BUF)
- pattern: $W.WriteString($S)
- pattern: $O.Body($BODY)
- pattern: fmt.Fprint($W, ...)
- pattern: fmt.Fprintf($W, ...)
- pattern: fmt.Fprintln($W, ...)
- pattern: io.WriteString($W, $S)
- pattern: json.NewEncoder($W).Encode($DATA)
- pattern: $C.ServeJSON()
- pattern: $O.JSON($DATA, ...)
pattern-sanitizers:
- pattern: template.HTMLEscapeString($X)
- pattern: template.JSEscapeString($X)
- pattern: template.URLQueryEscaper($X)
- pattern: template.HTMLEscaper($X)
- pattern: html.EscapeString($X)
- pattern: url.QueryEscape($X)
- pattern: url.PathEscape($X)
10 changes: 10 additions & 0 deletions rules/ruleset/go/lib/http-sources-header-index.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
rules:
- id: go-http-sources-header-index
options: {lib: true}
languages: [go]
severity: NOTE
message: Untrusted header-map source
mode: taint
pattern-sources:
- label: "$UNTRUSTED"
pattern: $X.Header($K)
10 changes: 10 additions & 0 deletions rules/ruleset/go/lib/http-sources-requesturi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
rules:
- id: go-http-sources-requesturi
options: {lib: true}
languages: [go]
severity: NOTE
message: Untrusted request URI source
mode: taint
pattern-sources:
- label: "$UNTRUSTED"
pattern: $R.RequestURI
77 changes: 77 additions & 0 deletions rules/ruleset/go/lib/http-sources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
rules:
- id: go-http-sources
options: {lib: true}
languages: [go]
severity: NOTE
message: Untrusted user input originates here
mode: taint
pattern-sources:
- label: "$UNTRUSTED"
pattern-either:
- pattern: "($R : *http.Request).FormValue($K)"
- pattern: "($R : *http.Request).PostFormValue($K)"
- pattern: "($R : *http.Request).FormFile($K)"
- pattern: "($R : *http.Request).Cookie($K)"
- pattern: "($R : *http.Request).Cookies()"
- pattern: "($R : *http.Request).MultipartReader()"
- pattern: "($R : *http.Request).Referer()"
- pattern: "($R : *http.Request).UserAgent()"
- pattern: $R.URL.Query()
- pattern: $R.URL.Query().Get($K)
- pattern: $R.URL.Path
- pattern: $R.URL.RawQuery
- pattern: $R.URL.RawPath
- pattern: $R.Header.Get($K)
- pattern: $R.Header[$K]
- pattern: $R.Header[$K][$I]
- pattern: $R.Form[$K]
- pattern: $R.Form[$K][$I]
- pattern: $R.PostForm[$K]
- pattern: $R.PostForm[$K][$I]
- pattern: $R.URL.Query()[$K]
- pattern: $R.URL.Query()[$K][$I]
- pattern: $R.Header.Values($K)
- pattern: $R.Form.Get($K)
- pattern: $R.PostForm.Get($K)
- pattern: $R.Body
- pattern: $R.GetBody
- pattern: $R.Form
- pattern: $R.PostForm
- pattern: $R.MultipartForm
- pattern: $R.Header
- pattern: $R.Trailer
- pattern: $R.URL
- pattern: os.Getenv($K)
- pattern: os.LookupEnv($K)
- pattern: os.Args
# beego Controller methods
- pattern: "($C : *web.Controller).GetString($K)"
- pattern: "($C : *web.Controller).GetString($K, $DEF)"
- pattern: "($C : *web.Controller).GetStrings($K)"
- pattern: "($C : *web.Controller).GetStrings($K, $DEF)"
- pattern: $C.GetStrings($K)[$IDX]
- pattern: $C.GetStrings($K, $DEF)[$IDX]
- pattern: "($C : *web.Controller).GetInt($K)"
- pattern: "($C : *web.Controller).GetInt($K, $DEF)"
- pattern: "($C : *web.Controller).GetInt8($K)"
- pattern: "($C : *web.Controller).GetInt16($K)"
- pattern: "($C : *web.Controller).GetInt32($K)"
- pattern: "($C : *web.Controller).GetInt64($K)"
- pattern: "($C : *web.Controller).GetUint8($K)"
- pattern: "($C : *web.Controller).GetUint16($K)"
- pattern: "($C : *web.Controller).GetUint32($K)"
- pattern: "($C : *web.Controller).GetUint64($K)"
- pattern: "($C : *web.Controller).GetFloat($K)"
- pattern: "($C : *web.Controller).GetBool($K)"
- pattern: "($C : *web.Controller).GetFile($K)"
- pattern: "($C : *web.Controller).GetFiles($K)"
- pattern: "($C : *web.Controller).GetSession($K)"
- pattern: "($C : *web.Controller).Input()"
- pattern: "($C : *web.Controller).ParseForm($PTR)"
# beego Context.Input methods (c.Ctx.Input.X)
- pattern: "($X : *context.BeegoInput).Param($K)"
- pattern: "($X : *context.BeegoInput).Params()"
- pattern: "($X : *context.BeegoInput).URI()"
- pattern: "($X : *context.BeegoInput).URL()"
- pattern: $X.RequestBody
- pattern: "($X : *context.BeegoInput).Bind($PTR)"
20 changes: 20 additions & 0 deletions rules/ruleset/go/security/cmdinj.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
rules:
- id: go-command-injection
languages: [go]
severity: ERROR
message: Tainted user input reaches OS command execution (command injection)
metadata:
cwe: CWE-78
short-description: Command injection
mode: join
join:
refs:
- rule: go/lib/http-sources.yaml#go-http-sources
as: src
- rule: go/lib/http-sources-header-index.yaml#go-http-sources-header-index
as: extra_header
- rule: go/lib/go-cmdi-sinks.yaml#go-cmdi-sinks
as: sink
on:
- 'src.$UNTRUSTED -> sink.$UNTRUSTED'
- 'extra_header.$UNTRUSTED -> sink.$UNTRUSTED'
17 changes: 17 additions & 0 deletions rules/ruleset/go/security/path-traversal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
rules:
- id: go-path-traversal
languages: [go]
severity: ERROR
message: Tainted user input reaches filesystem path (path traversal)
metadata:
cwe: CWE-22
short-description: Path traversal
mode: join
join:
refs:
- rule: go/lib/http-sources.yaml#go-http-sources
as: src
- rule: go/lib/go-path-sinks.yaml#go-path-sinks
as: sink
on:
- 'src.$UNTRUSTED -> sink.$UNTRUSTED'
23 changes: 23 additions & 0 deletions rules/ruleset/go/security/sql-injection.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
rules:
- id: go-sql-injection
languages: [go]
severity: ERROR
message: Tainted user input flows into SQL query (SQL injection)
metadata:
cwe: CWE-89
short-description: SQL injection
mode: join
join:
refs:
- rule: go/lib/http-sources.yaml#go-http-sources
as: src
- rule: go/lib/http-sources-requesturi.yaml#go-http-sources-requesturi
as: extra_requesturi
- rule: go/lib/http-sources-header-index.yaml#go-http-sources-header-index
as: extra_header
- rule: go/lib/go-sql-sinks.yaml#go-sql-sinks
as: sink
on:
- 'src.$UNTRUSTED -> sink.$UNTRUSTED'
- 'extra_requesturi.$UNTRUSTED -> sink.$UNTRUSTED'
- 'extra_header.$UNTRUSTED -> sink.$UNTRUSTED'
17 changes: 17 additions & 0 deletions rules/ruleset/go/security/ssrf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
rules:
- id: go-ssrf
languages: [go]
severity: ERROR
message: Tainted user input flows into a server-side HTTP request (SSRF)
metadata:
cwe: CWE-918
short-description: Server-side request forgery
mode: join
join:
refs:
- rule: go/lib/http-sources.yaml#go-http-sources
as: src
- rule: go/lib/go-ssrf-sinks.yaml#go-ssrf-sinks
as: sink
on:
- 'src.$UNTRUSTED -> sink.$UNTRUSTED'
17 changes: 17 additions & 0 deletions rules/ruleset/go/security/ssti.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
rules:
- id: go-ssti
languages: [go]
severity: ERROR
message: Tainted user input parsed as a template source (server-side template injection)
metadata:
cwe: CWE-1336
short-description: Server-side template injection
mode: join
join:
refs:
- rule: go/lib/http-sources.yaml#go-http-sources
as: src
- rule: go/lib/go-ssti-sinks.yaml#go-ssti-sinks
as: sink
on:
- 'src.$UNTRUSTED -> sink.$UNTRUSTED'
Loading
Loading