Convert XSS tests to use inline expectations

This commit is contained in:
Owen Mansel-Chan
2025-04-24 12:18:23 +01:00
parent 1530ac123c
commit 1926ffd450
11 changed files with 70 additions and 64 deletions

View File

@@ -26,45 +26,45 @@ func bad(req *http.Request) {
{
{
var a = template.HTML(req.UserAgent())
checkError(tmpl.Execute(os.Stdout, a))
var a = template.HTML(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmpl.Execute(os.Stdout, a)) // $ Alert[go/html-template-escaping-passthrough]
}
{
{
var a template.HTML
a = template.HTML(req.UserAgent())
checkError(tmpl.Execute(os.Stdout, a))
a = template.HTML(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmpl.Execute(os.Stdout, a)) // $ Alert[go/html-template-escaping-passthrough]
}
{
var a HTMLAlias
a = HTMLAlias(req.UserAgent())
checkError(tmpl.Execute(os.Stdout, a))
a = HTMLAlias(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmpl.Execute(os.Stdout, a)) // $ Alert[go/html-template-escaping-passthrough]
}
}
}
{
var c = template.HTMLAttr(req.UserAgent())
checkError(tmplTag.Execute(os.Stdout, c))
var c = template.HTMLAttr(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmplTag.Execute(os.Stdout, c)) // $ Alert[go/html-template-escaping-passthrough]
}
{
var d = template.JS(req.UserAgent())
checkError(tmplScript.Execute(os.Stdout, d))
var d = template.JS(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmplScript.Execute(os.Stdout, d)) // $ Alert[go/html-template-escaping-passthrough]
}
{
var e = template.JSStr(req.UserAgent())
checkError(tmplScript.Execute(os.Stdout, e))
var e = template.JSStr(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmplScript.Execute(os.Stdout, e)) // $ Alert[go/html-template-escaping-passthrough]
}
{
var b = template.CSS(req.UserAgent())
checkError(tmpl.Execute(os.Stdout, b))
var b = template.CSS(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmpl.Execute(os.Stdout, b)) // $ Alert[go/html-template-escaping-passthrough]
}
{
var f = template.Srcset(req.UserAgent())
checkError(tmplSrcset.Execute(os.Stdout, f))
var f = template.Srcset(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmplSrcset.Execute(os.Stdout, f)) // $ Alert[go/html-template-escaping-passthrough]
}
{
var g = template.URL(req.UserAgent())
checkError(tmpl.Execute(os.Stdout, g))
var g = template.URL(req.UserAgent()) // $ Source[go/html-template-escaping-passthrough]
checkError(tmpl.Execute(os.Stdout, g)) // $ Alert[go/html-template-escaping-passthrough]
}
}

View File

@@ -1,2 +1,4 @@
query: Security/CWE-079/HTMLTemplateEscapingPassthrough.ql
postprocess: utils/test/PrettyPrintModels.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,10 +8,10 @@ import (
func serve() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.Form.Get("username")
username := r.Form.Get("username") // $ Source[go/reflected-xss]
if !isValidUsername(username) {
// BAD: a request parameter is incorporated without validation into the response
fmt.Fprintf(w, "%q is an unknown user", username)
fmt.Fprintf(w, "%q is an unknown user", username) // $ Alert[go/reflected-xss]
} else {
// TODO: Handle successful login
}

View File

@@ -1,2 +1,4 @@
query: Security/CWE-079/ReflectedXss.ql
postprocess: utils/test/PrettyPrintModels.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -10,6 +10,6 @@ func ListFiles(w http.ResponseWriter, r *http.Request) {
files, _ := ioutil.ReadDir(".")
for _, file := range files {
io.WriteString(w, file.Name()+"\n")
io.WriteString(w, file.Name()+"\n") // $ Alert[go/stored-xss]
}
}

View File

@@ -1,2 +1,4 @@
query: Security/CWE-079/StoredXss.ql
postprocess: utils/test/PrettyPrintModels.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,13 +8,13 @@ import (
func serve2() {
http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
data := r.Form.Get("data")
data := r.Form.Get("data") // $ Source[go/reflected-xss]
// Not OK; direct flow from request body to output.
// The response Content-Type header is derived from a call to
// `http.DetectContentType`, which can be easily manipulated into returning
// `text/html` for XSS.
w.Write([]byte(data))
w.Write([]byte(data)) // $ Alert[go/reflected-xss]
})
http.ListenAndServe(":80", nil)
}
@@ -46,11 +46,11 @@ func serve4() {
func serve5() {
http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
data := r.Form.Get("data")
data := r.Form.Get("data") // $ Source[go/reflected-xss]
w.Header().Set("Content-Type", "text/html")
fmt.Fprintf(w, "Constant: %s", data) // Not OK; the content-type header is explicitly set to html
fmt.Fprintf(w, "Constant: %s", data) // $ Alert[go/reflected-xss] // The content-type header is explicitly set to html
})
http.ListenAndServe(":80", nil)
}
@@ -60,8 +60,8 @@ func serve10() {
r.ParseForm()
data := r.Form.Get("data")
data = r.FormValue("data")
fmt.Fprintf(w, "\t<html><body>%s</body></html>", data) // Not OK
data = r.FormValue("data") // $ Source[go/reflected-xss]
fmt.Fprintf(w, "\t<html><body>%s</body></html>", data) // $ Alert[go/reflected-xss]
})
}
@@ -70,13 +70,13 @@ func serve11() {
r.ParseForm()
data := r.Form.Get("data")
data = r.FormValue("data")
data = r.FormValue("data") // $ Source[go/reflected-xss]
fmt.Fprintf(w, `
<html>
<body>
%s
</body>
</html>`, data) // Not OK
</html>`, data) // $ Alert[go/reflected-xss]
})
}
@@ -85,10 +85,10 @@ func serve12() {
r.ParseForm()
data := r.Form.Get("data")
data = r.FormValue("data")
data = r.FormValue("data") // $ Source[go/reflected-xss]
fmt.Fprintf(w, `
%s
`, data) // Not OK
`, data) // $ Alert[go/reflected-xss]
})
}
@@ -110,7 +110,7 @@ func serve14() {
r.ParseForm()
data := r.Form.Get("data")
data = r.FormValue("data")
fmt.Fprintf(w, "<html><body>%s</body></html>", data) // Not OK
data = r.FormValue("data") // $ Source[go/reflected-xss]
fmt.Fprintf(w, "<html><body>%s</body></html>", data) // $ Alert[go/reflected-xss]
})
}

View File

@@ -28,29 +28,29 @@ func ErrTest(w http.ResponseWriter, r http.Request) {
w.Write([]byte(fmt.Sprintf("Cookie result: %v", cookie))) // GOOD: Cookie's value is not user-controlled in reflected xss.
w.Write([]byte(fmt.Sprintf("Cookie check error: %v", err))) // GOOD: Cookie's err return is harmless
http.Error(w, fmt.Sprintf("Cookie result: %v", cookie), 500) // Good: only plain text is written.
file, header, err := r.FormFile("someFile")
file, header, err := r.FormFile("someFile") // $ Source[go/reflected-xss]
content, err2 := ioutil.ReadAll(file)
w.Write([]byte(fmt.Sprintf("File content: %v", content))) // BAD: file content is user-controlled
w.Write([]byte(fmt.Sprintf("File name: %v", header.Filename))) // BAD: file header is user-controlled
w.Write([]byte(fmt.Sprintf("File content: %v", content))) // $ Alert[go/reflected-xss] // BAD: file content is user-controlled
w.Write([]byte(fmt.Sprintf("File name: %v", header.Filename))) // $ Alert[go/reflected-xss] // BAD: file header is user-controlled
w.Write([]byte(fmt.Sprintf("FormFile error: %v", err))) // GOOD: FormFile's err return is harmless
w.Write([]byte(fmt.Sprintf("FormFile error: %v", err2))) // GOOD: ReadAll's err return is harmless
reader, err := r.MultipartReader()
reader, err := r.MultipartReader() // $ Source[go/reflected-xss]
part, err2 := reader.NextPart()
partName := part.FileName()
byteSlice := make([]byte, 100)
part.Read(byteSlice)
w.Write([]byte(fmt.Sprintf("Part name: %v", partName))) // BAD: part name is user-controlled
w.Write(byteSlice) // BAD: part contents are user-controlled
w.Write([]byte(fmt.Sprintf("Part name: %v", partName))) // $ Alert[go/reflected-xss] // BAD: part name is user-controlled
w.Write(byteSlice) // $ Alert[go/reflected-xss] // BAD: part contents are user-controlled
w.Write([]byte(fmt.Sprintf("MultipartReader error: %v", err))) // GOOD: MultipartReader's err return is harmless
w.Write([]byte(fmt.Sprintf("MultipartReader error: %v", err2))) // GOOD: NextPart's err return is harmless
}
func QueryMapTest(w http.ResponseWriter, r http.Request) {
keys, ok := r.URL.Query()["data_id"]
keys, ok := r.URL.Query()["data_id"] // $ Source[go/reflected-xss]
if ok && len(keys[0]) > 0 {
key := keys[0]
w.Write([]byte(key)) // BAD: query string is user-controlled
w.Write([]byte(key)) // $ Alert[go/reflected-xss] // BAD: query string is user-controlled
}
}

View File

@@ -15,7 +15,7 @@ var q string
func storedserve1() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
rows, _ := db.Query(q, 32)
rows, _ := db.Query(q, 32) // $ Source[go/stored-xss]
for rows.Next() {
var (
@@ -27,7 +27,7 @@ func storedserve1() {
}
// BAD: the stored XSS query assumes all query results are untrusted
io.WriteString(w, name)
io.WriteString(w, name) // $ Alert[go/stored-xss]
}
})
}
@@ -56,9 +56,9 @@ func storedserve2() {
func storedserve3() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
filepath.WalkDir(".", func(path string, _ fs.DirEntry, err error) error {
filepath.WalkDir(".", func(path string, _ fs.DirEntry, err error) error { // $ Source[go/stored-xss]
// BAD: filenames are considered to be untrusted
io.WriteString(w, path)
io.WriteString(w, path) // $ Alert[go/stored-xss]
return nil
})
})

View File

@@ -11,11 +11,11 @@ import (
func serve6() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.Form.Get("username")
username := r.Form.Get("username") // $ Source[go/reflected-xss]
if !isValidUsername(username) {
// BAD: a request parameter is incorporated without validation into the response
a := []string{username, "is", "an", "unknown", "user"}
w.Write([]byte(strings.Join(a, " ")))
w.Write([]byte(strings.Join(a, " "))) // $ Alert[go/reflected-xss]
} else {
// TODO: do something exciting
}
@@ -45,12 +45,12 @@ func serve7() {
func serve8() {
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
service := r.Form.Get("service")
service := r.Form.Get("service") // $ Source[go/reflected-xss]
if service != "service1" && service != "service2" {
fmt.Fprintln(w, "Service not found")
} else {
// OK (service is known to be either "service1" or "service2" here), but currently flagged
w.Write([]byte(service))
w.Write([]byte(service)) // $ SPURIOUS: Alert[go/reflected-xss]
}
})
}

View File

@@ -27,32 +27,32 @@ func xss(w http.ResponseWriter, r *http.Request) {
origin := "test"
{
ws, _ := websocket.Dial(uri, "", origin)
var xnet = make([]byte, 512)
var xnet = make([]byte, 512) // $ Source[go/reflected-xss]
ws.Read(xnet)
fmt.Fprintf(w, "%v", xnet)
fmt.Fprintf(w, "%v", xnet) // $ Alert[go/reflected-xss]
codec := &websocket.Codec{marshal, unmarshal}
xnet2 := make([]byte, 512)
xnet2 := make([]byte, 512) // $ Source[go/reflected-xss]
codec.Receive(ws, xnet2)
fmt.Fprintf(w, "%v", xnet2)
fmt.Fprintf(w, "%v", xnet2) // $ Alert[go/reflected-xss]
}
{
n, _, _ := nhooyr.Dial(context.TODO(), uri, nil)
_, nhooyr, _ := n.Read(context.TODO())
fmt.Fprintf(w, "%v", nhooyr)
_, nhooyr, _ := n.Read(context.TODO()) // $ Source[go/reflected-xss]
fmt.Fprintf(w, "%v", nhooyr) // $ Alert[go/reflected-xss]
}
{
dialer := gorilla.Dialer{}
conn, _, _ := dialer.Dial(uri, nil)
var gorillaMsg = make([]byte, 512)
var gorillaMsg = make([]byte, 512) // $ Source[go/reflected-xss]
gorilla.ReadJSON(conn, gorillaMsg)
fmt.Fprintf(w, "%v", gorillaMsg)
fmt.Fprintf(w, "%v", gorillaMsg) // $ Alert[go/reflected-xss]
gorilla2 := make([]byte, 512)
gorilla2 := make([]byte, 512) // $ Source[go/reflected-xss]
conn.ReadJSON(gorilla2)
fmt.Fprintf(w, "%v", gorilla2)
fmt.Fprintf(w, "%v", gorilla2) // $ Alert[go/reflected-xss]
_, gorilla3, _ := conn.ReadMessage()
fmt.Fprintf(w, "%v", gorilla3)
_, gorilla3, _ := conn.ReadMessage() // $ Source[go/reflected-xss]
fmt.Fprintf(w, "%v", gorilla3) // $ Alert[go/reflected-xss]
}
}