Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit 3758c6b

Browse files
authored
Merge pull request #329 from smowton/smowton/feature/xss-detect-more-json-encoding
Reflected XSS query: exclude more uses of encoding/json.Marshal
2 parents baf048f + 405babf commit 3758c6b

File tree

4 files changed

+41
-7
lines changed

4 files changed

+41
-7
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* The query "Reflected cross-site scripting" (`go/reflected-xss`) now recognizes more cases of JSON marshaled data, which cannot serve as a vector for an XSS attack. This may reduce false-positive results for this query.

ql/src/semmle/go/security/ReflectedXssCustomizations.qll

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,6 @@ module ReflectedXss {
7676
// https://mimesniff.spec.whatwg.org/#whitespace-byte) cannot cause an HTML content type to
7777
// be detected.
7878
pred.getStringValue().regexpMatch("(?s)[\\t\\n\\x0c\\r ]*+[^<].*")
79-
or
80-
// json data cannot begin with `<`
81-
exists(EncodingJson::MarshalFunction mf | pred = mf.getOutput().getNode(mf.getACall()))
8279
)
8380
)
8481
}
@@ -117,4 +114,16 @@ module ReflectedXss {
117114
outcome = this.getPolarity()
118115
}
119116
}
117+
118+
/**
119+
* A JSON marshaler, acting to sanitize a possible XSS vulnerability because the
120+
* marshaled value is very unlikely to be returned as an HTML content-type.
121+
*/
122+
class JsonMarshalSanitizer extends Sanitizer {
123+
JsonMarshalSanitizer() {
124+
exists(MarshalingFunction mf | mf.getFormat() = "JSON" |
125+
this = mf.getOutput().getNode(mf.getACall())
126+
)
127+
}
128+
}
120129
}

ql/test/query-tests/Security/CWE-079/ReflectedXss.expected

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
edges
2-
| ReflectedXss.go:11:15:11:20 | selection of Form : Values | ReflectedXss.go:14:44:14:51 | username |
2+
| ReflectedXss.go:12:15:12:20 | selection of Form : Values | ReflectedXss.go:15:44:15:51 | username |
33
| contenttype.go:11:11:11:16 | selection of Form : Values | contenttype.go:17:11:17:22 | type conversion |
44
| contenttype.go:49:11:49:16 | selection of Form : Values | contenttype.go:53:34:53:37 | data |
55
| contenttype.go:63:10:63:28 | call to FormValue : string | contenttype.go:64:52:64:55 | data |
@@ -15,8 +15,8 @@ edges
1515
| websocketXss.go:50:3:50:10 | definition of gorilla2 : slice type | websocketXss.go:52:24:52:31 | gorilla2 |
1616
| websocketXss.go:54:3:54:38 | ... := ...[1] : slice type | websocketXss.go:55:24:55:31 | gorilla3 |
1717
nodes
18-
| ReflectedXss.go:11:15:11:20 | selection of Form : Values | semmle.label | selection of Form : Values |
19-
| ReflectedXss.go:14:44:14:51 | username | semmle.label | username |
18+
| ReflectedXss.go:12:15:12:20 | selection of Form : Values | semmle.label | selection of Form : Values |
19+
| ReflectedXss.go:15:44:15:51 | username | semmle.label | username |
2020
| contenttype.go:11:11:11:16 | selection of Form : Values | semmle.label | selection of Form : Values |
2121
| contenttype.go:17:11:17:22 | type conversion | semmle.label | type conversion |
2222
| contenttype.go:49:11:49:16 | selection of Form : Values | semmle.label | selection of Form : Values |
@@ -46,7 +46,7 @@ nodes
4646
| websocketXss.go:54:3:54:38 | ... := ...[1] : slice type | semmle.label | ... := ...[1] : slice type |
4747
| websocketXss.go:55:24:55:31 | gorilla3 | semmle.label | gorilla3 |
4848
#select
49-
| ReflectedXss.go:14:44:14:51 | username | ReflectedXss.go:11:15:11:20 | selection of Form : Values | ReflectedXss.go:14:44:14:51 | username | Cross-site scripting vulnerability due to $@. | ReflectedXss.go:11:15:11:20 | selection of Form | user-provided value |
49+
| ReflectedXss.go:15:44:15:51 | username | ReflectedXss.go:12:15:12:20 | selection of Form : Values | ReflectedXss.go:15:44:15:51 | username | Cross-site scripting vulnerability due to $@. | ReflectedXss.go:12:15:12:20 | selection of Form | user-provided value |
5050
| contenttype.go:17:11:17:22 | type conversion | contenttype.go:11:11:11:16 | selection of Form : Values | contenttype.go:17:11:17:22 | type conversion | Cross-site scripting vulnerability due to $@. | contenttype.go:11:11:11:16 | selection of Form | user-provided value |
5151
| contenttype.go:53:34:53:37 | data | contenttype.go:49:11:49:16 | selection of Form : Values | contenttype.go:53:34:53:37 | data | Cross-site scripting vulnerability due to $@. | contenttype.go:49:11:49:16 | selection of Form | user-provided value |
5252
| contenttype.go:64:52:64:55 | data | contenttype.go:63:10:63:28 | call to FormValue : string | contenttype.go:64:52:64:55 | data | Cross-site scripting vulnerability due to $@. | contenttype.go:63:10:63:28 | call to FormValue | user-provided value |

ql/test/query-tests/Security/CWE-079/ReflectedXss.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"net/http"
67
)
@@ -18,3 +19,25 @@ func serve() {
1819
})
1920
http.ListenAndServe(":80", nil)
2021
}
22+
23+
func encode(s string) ([]byte, error) {
24+
25+
return json.Marshal(s)
26+
27+
}
28+
29+
func ServeJsonIndirect(w http.ResponseWriter, r http.Request) {
30+
31+
tainted := r.Header.Get("Origin")
32+
noLongerTainted, _ := encode(tainted)
33+
w.Write(noLongerTainted)
34+
35+
}
36+
37+
func ServeJsonDirect(w http.ResponseWriter, r http.Request) {
38+
39+
tainted := r.Header.Get("Origin")
40+
noLongerTainted, _ := json.Marshal(tainted)
41+
w.Write(noLongerTainted)
42+
43+
}

0 commit comments

Comments
 (0)