go.gorilla.security.audit.handler-attribute-read-from-multiple-sources.handler-attribute-read-from-multiple-sources

Author
225
Download Count*
License
Attribute $ATT is read from two different sources: '$X.$ATT' and '$Y.$ATT'. Make sure this is intended, as this could cause logic bugs if they are treated as if they are the same object.
Run Locally
Run in CI
Defintion
rules:
- id: handler-attribute-read-from-multiple-sources
metadata:
cwe: "CWE-289: Authentication Bypass by Alternate Name"
owasp: "A2: Broken Authentication"
owaspapi: "API1: Broken Object Level Authorization"
category: security
technology:
- gorilla
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
patterns:
- pattern-inside: |
func $HANDLER(..., $R *http.Request, ...) {
...
}
- pattern-either:
- pattern: |
$A = $X.$ATT
...
$B = $Y.$ATT
- pattern: $A = $X.$ATT || $Y.$ATT
message: "Attribute $ATT is read from two different sources: '$X.$ATT' and
'$Y.$ATT'. Make sure this is intended, as this could cause logic bugs if
they are treated as if they are the same object."
languages:
- go
severity: WARNING
Examples
handler-attribute-read-from-multiple-sources.go
package main
import (
"net/http"
"github.com/gorilla/sessions"
)
type User struct {
user_id int
account_id string
}
func ValidateUser(user_id int) bool {
return true
}
func RetrieveUser(user_id int) User {
return User{user_id, "0000"}
}
var store = sessions.NewCookieStore([]byte("blah-blah-blah"))
func MyHandler(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "blah-session")
// ruleid: handler-attribute-read-from-multiple-sources
user_id := session.user_id
if !ValidateUser(user_id) {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
user_id = r.query.params.user_id
user_obj := RetrieveUser(user_id)
user_obj.account_id = r.query.params.account_id
user_obj.save()
}
func MyHandlerDict(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "blah-session")
// ruleid: handler-attribute-read-from-multiple-sources-dict
user_id := session.Values["user_id"]
if !ValidateUser(user_id) {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
user_id = r.query.params.user_id
user_obj := RetrieveUser(user_id)
user_obj.account_id = r.query.params.account_id
user_obj.save()
}
func MyHandlerOr(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "blah-session")
// ruleid: handler-attribute-read-from-multiple-sources-dict
user_id := session.Values["user_id"] || r.query.params.user_id
// ruleid: handler-attribute-read-from-multiple-sources-dict
account_id := r.query.params.account_id || session.Values["account_id"]
r.ParseForm()
// ruleid: handler-attribute-read-from-multiple-sources-dict
other_id := r.query.params.other_id || r.FormValue("other_id")
if !ValidateUser(user_id) {
http.Error(w, "Error", http.StatusInternalServerError)
return
}
user_obj := RetrieveUser(user_id)
user_obj.account_id = account_id
user_obj.save()
}
func main() {
http.HandleFunc("/account", MyHandler)
http.ListenAndServe(":8080", nil)
}
Short Link: https://sg.run/Q5dx