Skip to content

Commit 1139ec9

Browse files
committed
Add extra replace sanitizers to StringBreak
1 parent bde155b commit 1139ec9

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

go/ql/lib/semmle/go/security/StringBreakCustomizations.qll

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,67 @@ module StringBreak {
105105

106106
override Quote getQuote() { result = quote }
107107
}
108+
109+
class StringsNewReplacerCall extends DataFlow::CallNode {
110+
StringsNewReplacerCall() { this.getTarget().hasQualifiedName("strings", "NewReplacer") }
111+
112+
DataFlow::Node getAReplacedArgument() {
113+
exists(int m, int n | m = 2 * n and n = m / 2 and result = getArgument(m))
114+
}
115+
}
116+
117+
class StringsNewReplacerConfiguration extends DataFlow2::Configuration {
118+
StringsNewReplacerConfiguration() { this = "StringsNewReplacerConfiguration" }
119+
120+
override predicate isSource(DataFlow::Node source) { source instanceof StringsNewReplacerCall }
121+
122+
override predicate isSink(DataFlow::Node sink) {
123+
exists(DataFlow::MethodCallNode call |
124+
sink = call.getReceiver() and
125+
call.getTarget().hasQualifiedName("strings", "Replacer", ["Replace", "WriteString"])
126+
)
127+
}
128+
}
129+
130+
/**
131+
* A call to `strings.Replacer.Replace`, considered as a sanitizer for unsafe
132+
* quoting.
133+
*/
134+
class ReplacerReplaceSanitizer extends DataFlow::MethodCallNode, Sanitizer {
135+
Quote quote;
136+
137+
ReplacerReplaceSanitizer() {
138+
exists(StringsNewReplacerConfiguration config, DataFlow::Node source, DataFlow::Node sink |
139+
config.hasFlow(source, sink) and
140+
this.getTarget().hasQualifiedName("strings", "Replacer", "Replace") and
141+
sink = this.getReceiver() and
142+
quote = source.(StringsNewReplacerCall).getAReplacedArgument().getStringValue()
143+
)
144+
}
145+
146+
override Quote getQuote() { result = quote }
147+
}
148+
149+
/**
150+
* A call to `strings.Replacer.WriteString`, considered as a sanitizer for
151+
* unsafe quoting.
152+
*/
153+
class ReplacerWriteStringSanitizer extends Sanitizer {
154+
Quote quote;
155+
156+
ReplacerWriteStringSanitizer() {
157+
exists(
158+
StringsNewReplacerConfiguration config, DataFlow::Node source, DataFlow::Node sink,
159+
DataFlow::MethodCallNode call
160+
|
161+
config.hasFlow(source, sink) and
162+
call.getTarget().hasQualifiedName("strings", "Replacer", "WriteString") and
163+
sink = call.getReceiver() and
164+
this = call.getArgument(1) and
165+
quote = source.(StringsNewReplacerCall).getAReplacedArgument().getStringValue()
166+
)
167+
}
168+
169+
override Quote getQuote() { result = quote }
170+
}
108171
}

go/ql/test/query-tests/Security/CWE-089/StringBreakGood.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package main
22

33
import (
4+
"bytes"
45
"encoding/json"
5-
sq "github.com/Masterminds/squirrel"
66
"strings"
7+
8+
sq "github.com/Masterminds/squirrel"
79
)
810

911
// Good because there is no concatenation with quotes:
@@ -37,3 +39,28 @@ func saveGood3(id string, version interface{}) {
3739
Values(id, sq.Expr("'"+escaped+"'")).
3840
Exec()
3941
}
42+
43+
var globalReplacer = strings.NewReplacer("\"", "", "'", "")
44+
45+
// Good because quote characters are removed before concatenation:
46+
func saveGood4(id string, version interface{}) {
47+
versionJSON, _ := json.Marshal(version)
48+
escaped := globalReplacer.Replace(string(versionJSON))
49+
sq.StatementBuilder.
50+
Insert("resources").
51+
Columns("resource_id", "version_md5").
52+
Values(id, sq.Expr("'"+escaped+"'")).
53+
Exec()
54+
}
55+
56+
// Good because quote characters are removed before concatenation:
57+
func saveGood5(id string, version interface{}) {
58+
versionJSON, _ := json.Marshal(version)
59+
buf := new(bytes.Buffer)
60+
globalReplacer.WriteString(buf, string(versionJSON))
61+
sq.StatementBuilder.
62+
Insert("resources").
63+
Columns("resource_id", "version_md5").
64+
Values(id, sq.Expr("'"+buf.String()+"'")).
65+
Exec()
66+
}

0 commit comments

Comments
 (0)