diff --git a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 2405d6ddd4e..8a57aea8d69 100644 --- a/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/python/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -15,16 +15,20 @@ import semmle.python.dataflow.new.DataFlow import semmle.python.Concepts import experimental.semmle.python.Concepts -from HeaderDeclaration headerWrite, False f, None n +from Expr cookieExpr, False f, None n where - exists(StrConst headerName, StrConst headerValue | + exists(HeaderDeclaration headerWrite, StrConst headerName, StrConst headerValue | headerName.getText() = "Set-Cookie" and DataFlow::exprNode(headerName).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getNameArg()) and not headerValue.getText().regexpMatch(".*; *Secure;.*") and - DataFlow::exprNode(headerValue).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getValueArg()) + DataFlow::exprNode(headerValue).(DataFlow::LocalSourceNode).flowsTo(headerWrite.getValueArg()) and + cookieExpr = headerWrite.asExpr() ) or - [DataFlow::exprNode(f), DataFlow::exprNode(n)] - .(DataFlow::LocalSourceNode) - .flowsTo(headerWrite.(DataFlow::CallCfgNode).getArgByName("secure")) -select headerWrite, "Cookie is added to response without the 'secure' flag being set." + exists(ExperimentalHTTP::CookieWrite cookieWrite | + [DataFlow::exprNode(f), DataFlow::exprNode(n)] + .(DataFlow::LocalSourceNode) + .flowsTo(cookieWrite.(DataFlow::CallCfgNode).getArgByName("secure")) and + cookieExpr = cookieWrite.asExpr() + ) +select cookieExpr, "Cookie is added to response without the 'secure' flag being set." diff --git a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll index 9c66d9a4601..2a2cc68fe84 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/Flask.qll @@ -81,4 +81,20 @@ module ExperimentalFlask { override DataFlow::Node getValueArg() { result.asExpr() = item.getValue() } } + + class DjangoSetCookieCall extends DataFlow::CallCfgNode, ExperimentalHTTP::CookieWrite::Range { + DjangoSetCookieCall() { + this = + [Flask::Response::classRef(), flaskMakeResponse()] + .getReturn() + .getMember("set_cookie") + .getACall() + } + + override DataFlow::Node getHeaderArg() { none() } + + override DataFlow::Node getNameArg() { result = this.getArg(0) } + + override DataFlow::Node getValueArg() { result = this.getArg(1) } + } } diff --git a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py index 877231f8f14..02752d32f99 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-614/django_bad.py @@ -9,5 +9,5 @@ def django_response(request): def django_response(request): resp = django.http.HttpResponse() - resp.set_cookie("name", "value") + resp.set_cookie("name", "value", secure=False) return resp