diff --git a/go/ql/src/experimental/CWE-639/urlCheck.ql b/go/ql/src/experimental/CWE-639/urlCheck.ql new file mode 100644 index 0000000000000..a8d882f7a63ad --- /dev/null +++ b/go/ql/src/experimental/CWE-639/urlCheck.ql @@ -0,0 +1,67 @@ +/** + * @name Incorrect check on url + * @description If a CORS policy is configured to accept an origin value obtained from the request data, it can lead to a policy bypass. + * @kind path-problem + * @problem.severity warning + * @id go/cors-bypass + * @tags security + * experimental + * external/cwe/cwe-942 + * external/cwe/cwe-346 + */ + +import go +import codeql.dataflow.TaintTracking +import semmle.go.dataflow.TaintTracking + +bindingset[s] +predicate mayBeCors(string s) { s.toLowerCase().matches(["%origin%", "%cors%"]) } + +class MaybeOrigin extends RemoteFlowSource { + MaybeOrigin() { + none() + // exists(RemoteFlowSource r | + // // Any write where the variables name could suggest it has something to do with cors. + // exists(Write w, Variable v | + // mayBeCors(w.getLhs().getName()) + // or + // v.getAWrite() = w and mayBeCors(v.getName()) + // | + // w = r.getASuccessor*().asInstruction() + // ) + // or + // // Any argument or a receiver whose name could suggest it has something to do with cors. + // exists(DataFlow::CallNode c, DataFlow::ArgumentNode a | + // c.getArgument(_) = r.getASuccessor*() + // or + // c.getReceiver() = r.getASuccessor*() and + // a.argumentOf(c.asExpr(), _) and + // mayBeCors(a.getStringValue()) + // | + // mayBeCors([c.getTarget().getName()]) + // ) + // | + // this = r + // ) + } +} + +module UrlFlow implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node instanceof MaybeOrigin } + + predicate isSink(DataFlow::Node node) { + exists(DataFlow::CallNode mc | + mc.getTarget().hasQualifiedName("strings", "HasSuffix") and + not mc.getArgument(1).asExpr().(StringLit).getExactValue().matches(".%") + | + mc.getArgument(0) = node + // and node. + ) + } +} + +module Flow = TaintTracking::Global; + +from DataFlow::Node source, DataFlow::Node sink +where Flow::flow(source, sink) +select sink, "asd"