Skip to content

Commit e7e4286

Browse files
authored
Merge pull request #19561 from owen-mc/go/mad/bigquery-sql-injection-sink
Go: Add BigQuery as a sink for SQLi queries #2
2 parents 0ef17ba + fb92999 commit e7e4286

File tree

11 files changed

+1400
-1
lines changed

11 files changed

+1400
-1
lines changed

go/documentation/library-coverage/frameworks.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Standard library,https://pkg.go.dev/std, archive/* bufio bytes cmp compress/* co
33
appleboy/gin-jwt,https://github.com/appleboy/gin-jwt,github.com/appleboy/gin-jwt*
44
Afero,https://github.com/spf13/afero,github.com/spf13/afero*
55
beego,https://beego.me/,github.com/astaxie/beego* github.com/beego/beego*
6+
bigquery,https://pkg.go.dev/cloud.google.com/go/bigquery,cloud.google.com/go/bigquery*
67
Bun,https://bun.uptrace.dev/,github.com/uptrace/bun*
78
CleverGo,https://github.com/clevergo/clevergo,clevergo.tech/clevergo* github.com/clevergo/clevergo*
89
Couchbase official client(gocb),https://github.com/couchbase/gocb,github.com/couchbase/gocb* gopkg.in/couchbase/gocb*
@@ -35,7 +36,7 @@ golang.org/x/net,https://pkg.go.dev/golang.org/x/net,golang.org/x/net*
3536
goproxy,https://github.com/elazarl/goproxy,github.com/elazarl/goproxy*
3637
gorilla/mux,https://github.com/gorilla/mux,github.com/gorilla/mux*
3738
gorilla/websocket,https://github.com/gorilla/websocket,github.com/gorilla/websocket*
38-
gorqlite,https://github.com/rqlite/gorqlite,github.com/raindog308/gorqlite* github.com/rqlite/gorqlite*
39+
gorqlite,https://github.com/rqlite/gorqlite,github.com/raindog308/gorqlite* github.com/rqlite/gorqlite* github.com/kanikanema/gorqlite*
3940
goxpath,https://github.com/ChrisTrenkamp/goxpath/wiki,github.com/ChrisTrenkamp/goxpath*
4041
htmlquery,https://github.com/antchfx/htmlquery,github.com/antchfx/htmlquery*
4142
Iris,https://www.iris-go.com/,github.com/kataras/iris*
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The first argument of `Client.Query` in `cloud.google.com/go/bigquery` is now recognized as a SQL injection sink.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/go-all
4+
extensible: sinkModel
5+
data:
6+
- ["cloud.google.com/go/bigquery", "Client", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
invalidModelRow
2+
testFailures
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import go
2+
import semmle.go.dataflow.ExternalFlow
3+
import ModelValidation
4+
import utils.test.InlineExpectationsTest
5+
6+
module SqlTest implements TestSig {
7+
string getARelevantTag() { result = "query" }
8+
9+
predicate hasActualResult(Location location, string element, string tag, string value) {
10+
tag = "query" and
11+
exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() |
12+
q.getLocation() = location and
13+
element = q.toString() and
14+
value = qs.toString()
15+
)
16+
}
17+
}
18+
19+
module QueryString implements TestSig {
20+
string getARelevantTag() { result = "querystring" }
21+
22+
predicate hasActualResult(Location location, string element, string tag, string value) {
23+
tag = "querystring" and
24+
element = "" and
25+
exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) |
26+
qs.getLocation() = location and
27+
value = qs.toString()
28+
)
29+
}
30+
}
31+
32+
module Config implements DataFlow::ConfigSig {
33+
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit }
34+
35+
predicate isSink(DataFlow::Node n) {
36+
n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument()
37+
}
38+
}
39+
40+
module Flow = TaintTracking::Global<Config>;
41+
42+
module TaintFlow implements TestSig {
43+
string getARelevantTag() { result = "flowfrom" }
44+
45+
predicate hasActualResult(Location location, string element, string tag, string value) {
46+
tag = "flowfrom" and
47+
element = "" and
48+
exists(DataFlow::Node fromNode, DataFlow::Node toNode |
49+
toNode.getLocation() = location and
50+
Flow::flow(fromNode, toNode) and
51+
value = fromNode.asExpr().(StringLit).getValue()
52+
)
53+
}
54+
}
55+
56+
import MakeTest<MergeTests3<SqlTest, QueryString, TaintFlow>>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| bigquery.go:17:15:17:23 | untrusted | cloud.google.com/go/bigquery.Client | Query |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package main
2+
3+
//go:generate depstubber -vendor cloud.google.com/go/bigquery Client
4+
5+
import (
6+
"cloud.google.com/go/bigquery"
7+
)
8+
9+
func getUntrustedString() string {
10+
return "trouble"
11+
}
12+
13+
func main() {
14+
untrusted := getUntrustedString()
15+
var client *bigquery.Client
16+
17+
client.Query(untrusted) // $ querystring=untrusted
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import go
2+
3+
from SQL::QueryString qs, Function func, string a, string b
4+
where
5+
func.hasQualifiedName(a, b) and
6+
qs = func.getACall().getSyntacticArgument(_)
7+
select qs, a, b
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module bigquerytest
2+
3+
go 1.24
4+
5+
require cloud.google.com/go/bigquery v1.68.0
6+
7+
require (
8+
cloud.google.com/go v0.121.0 // indirect
9+
cloud.google.com/go/auth v0.16.1 // indirect
10+
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
11+
cloud.google.com/go/compute/metadata v0.6.0 // indirect
12+
cloud.google.com/go/iam v1.5.2 // indirect
13+
github.com/apache/arrow/go/v15 v15.0.2 // indirect
14+
github.com/felixge/httpsnoop v1.0.4 // indirect
15+
github.com/go-logr/logr v1.4.2 // indirect
16+
github.com/go-logr/stdr v1.2.2 // indirect
17+
github.com/goccy/go-json v0.10.2 // indirect
18+
github.com/google/flatbuffers v23.5.26+incompatible // indirect
19+
github.com/google/s2a-go v0.1.9 // indirect
20+
github.com/google/uuid v1.6.0 // indirect
21+
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
22+
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
23+
github.com/klauspost/compress v1.16.7 // indirect
24+
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
25+
github.com/pierrec/lz4/v4 v4.1.18 // indirect
26+
github.com/zeebo/xxh3 v1.0.2 // indirect
27+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
28+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
29+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
30+
go.opentelemetry.io/otel v1.35.0 // indirect
31+
go.opentelemetry.io/otel/metric v1.35.0 // indirect
32+
go.opentelemetry.io/otel/trace v1.35.0 // indirect
33+
golang.org/x/crypto v0.37.0 // indirect
34+
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
35+
golang.org/x/mod v0.23.0 // indirect
36+
golang.org/x/net v0.39.0 // indirect
37+
golang.org/x/oauth2 v0.29.0 // indirect
38+
golang.org/x/sync v0.14.0 // indirect
39+
golang.org/x/sys v0.32.0 // indirect
40+
golang.org/x/text v0.24.0 // indirect
41+
golang.org/x/time v0.11.0 // indirect
42+
golang.org/x/tools v0.30.0 // indirect
43+
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
44+
google.golang.org/api v0.231.0 // indirect
45+
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
46+
google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect
47+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect
48+
google.golang.org/grpc v1.72.0 // indirect
49+
google.golang.org/protobuf v1.36.6 // indirect
50+
)

0 commit comments

Comments
 (0)