diff --git a/ql/src/semmle/go/frameworks/Revel.qll b/ql/src/semmle/go/frameworks/Revel.qll index 259513f126f..1bd33768b66 100644 --- a/ql/src/semmle/go/frameworks/Revel.qll +++ b/ql/src/semmle/go/frameworks/Revel.qll @@ -185,4 +185,34 @@ module Revel { override HTTP::ResponseWriter getResponseWriter() { none() } } + + /** + * The getter and setter methods of `revel.RevelHeader`. + * + * Note we currently don't implement `HeaderWrite` and related concepts, as they are currently only used + * to track content-type, and directly setting headers does not seem to be the usual way to set the response + * content-type for this framework. If and when the `HeaderWrite` concept has a more abstract idea of the + * relationship between header-writes and HTTP responses than looking for a particular `http.ResponseWriter` + * instance connecting the two, then we may implement it here for completeness. + */ + private class RevelHeaderMethods extends TaintTracking::FunctionModel { + FunctionInput input; + FunctionOutput output; + string name; + + RevelHeaderMethods() { + this.(Method).hasQualifiedName(packagePath(), "RevelHeader", name) and + ( + name = ["Add", "Set"] and input.isParameter([0, 1]) and output.isReceiver() + or + name = ["Get", "GetAll"] and input.isReceiver() and output.isResult() + or + name = "SetCookie" and input.isParameter(0) and output.isReceiver() + ) + } + + override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) { + inp = input and outp = output + } + } } diff --git a/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go b/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go index ae59e7d1f51..7391b2506f2 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go +++ b/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go @@ -126,3 +126,11 @@ func accessingServerRequest(c *revel.Controller) { c.Request.WebSocket.MessageReceiveJSON(&p) // NOT OK usePerson(p) } + +func accessingHeaders(c *revel.Controller) { + tainted := c.Request.Header.Get("somekey") // NOT OK + useString(tainted) + + tainted2 := c.Request.Header.GetAll("somekey") // NOT OK + useString(tainted2[0]) +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Revel/TaintFlows.expected b/ql/test/library-tests/semmle/go/frameworks/Revel/TaintFlows.expected index 51be68608b2..fe8b9115a71 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Revel/TaintFlows.expected +++ b/ql/test/library-tests/semmle/go/frameworks/Revel/TaintFlows.expected @@ -39,3 +39,5 @@ | Revel.go:117:12:117:32 | call to UserAgent | Revel.go:117:12:117:32 | call to UserAgent | 117 | | Revel.go:122:37:122:44 | &... : pointer type | Revel.go:123:12:123:18 | message | 122 | | Revel.go:126:41:126:42 | &... : pointer type | Revel.go:127:12:127:12 | p | 126 | +| Revel.go:131:13:131:28 | selection of Header : pointer type | Revel.go:132:12:132:18 | tainted | 131 | +| Revel.go:134:14:134:29 | selection of Header : pointer type | Revel.go:135:12:135:22 | index expression | 134 |