Bento check: keeping your cookies safe in Flask

Ensure cookie settings are set securely in Flask

get this check now in Bento:

Get this check in Semgrep:

1brew install semgrep && \
2semgrep --config "https://semgrep.dev/p/python-flask"

Cookies! 🍪🥠 Those little bits of data that I occasionally remember to purge from my browser.

In 2011, RFC6265 was accepted, which introduced new mechanisms for managing cookies. The document introduced the unhelpfully-named HttpOnly flag, which instructs a browser to forbid scripts from accessing the cookie. This mitigates XSS attacks that target cookies. RFC6265 also updated the definition for the Secure flag, which instructs the browser to only transmit the cookie over HTTPS. A new draft RFC adds even more cookie security settings, including the SameSite attribute, which permits or denies the browser the ability to send cookies with cross-site requests, mitigating CSRF attacks. Browsers have been adopting these settings for some time, and server frameworks like Flask support setting these attributes easily.

The check introduced in this post looks for Flask calls to set_cookie() where the secure, httponly, and samesite keyword arguments are not explicitly set.

1# Example
2response.set_cookie("name", "value", secure=True, httponly=True, samesite='Lax')

Flask's security recommendations suggest using Secure, HttpOnly, and SameSite where appropriate. Following this suggestion, the check detects cookies that are not set with these attributes. However, there are circumstances where some of these attributes do not need to be set. Therefore, the check permits explicit disabling. By doing this, it encourages developers to be explicit about how each cookie is handled.

The check will detect cases where none or some, but not all, of these keyword arguments are set:

1# None set
2from flask import make_response
3@app.route("/none_set")
4def none_set():
5    response = make_response()
6    response.set_cookie("cookie_name", "cookie_value")
7    return response
1# Some set
2@app.route("/some_set")
3def some_set():
4    r = make_response()
5
6    # some flags are set but not others
7    r.set_cookie("cookie1", "cookie_value", secure=True)
8    r.set_cookie("cookie2", "cookie_value", httponly=True)
9    r.set_cookie("cookie3", "cookie_value", samesite='Lax')
10    r.set_cookie("cookie4", "cookie_value", secure=True, httponly=True)
11    r.set_cookie("cookie5", "cookie_value", httponly=True, samesite='Lax')
12    return r

The check considers these cases acceptable:

1import flask
2@app.route("/")
3def index():
4    response = flask.make_response()
5    response.set_cookie("cookie1", "cookie_value", secure=True, httponly=True, samesite='Lax')
6    response.set_cookie("cookie2", "cookie_value", secure=True, httponly=True, samesite='Strict')
7    response.set_cookie("cookie3", "cookie_value", secure=False, httponly=False, samesite=None)
8    return response

I wondered if this check would fall under the category of annoying security recommendations and turned to our program analysis platform to see how frequently it fires. Of the 715 Flask apps on GitHub we used as a test set, the check fires in 18 repositories for a total of 66 instances. Reading the code, most of these projects would experience no drawback from using these secure cookie settings. This gives me some confidence that this check feels more like a friendly reminder instead of a bothersome decree! Speaking of friendly reminders, we are drafting PRs for these findings.

Histogram of r2c-flask-secure-set-cookie

You can check your own codebase for instances of this check right now with Bento:

1$ pip3 install bento-cli && bento init

References

About

Semgrep Logo

Semgrep lets security teams partner with developers and shift left organically, without introducing friction. Semgrep gives security teams confidence that they are only surfacing true, actionable issues to developers, and makes it easy for developers to fix these issues in their existing environments.

Find and fix the issues that matter before build time

Semgrep helps organizations shift left without the developer productivity tax.

Get started in minutesBook a demo