OD112 csrf-disabled¶
An HTTP route disables CSRF protection.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Security | Info | all | no |
What it reports¶
An @http.route of type http, the default, that passes csrf=False. This is a hotspot: code to
review, not a confirmed flaw.
Why it matters¶
For an http route, Odoo refuses a POST or any other method that can change data unless the
request carries the csrf_token of the user's session. A page on another site cannot read that
token, so it cannot make the user's browser submit a form to Odoo on their behalf. With
csrf=False, the session cookie is the only check, and unless the browser's cookie policy holds it
back, a signed-in user who opens a hostile page submits its form with their rights, without
knowing. Add the token to the form instead, as a hidden csrf_token input.
Turning the check off is right for an endpoint called by another server, such as a payment
provider's webhook, which has no session and must prove itself another way, for example by a
signature the route verifies. Review that check and suppress the finding. json routes are not
reported, since Odoo does not check CSRF tokens on them.
Example¶
class PreferencesController(http.Controller):
@http.route("/my/language", type="http", auth="user", methods=["POST"], csrf=False)
def set_language(self, lang):
request.env.user.write({"lang": lang})
return request.redirect("/my")
Any site the user visits can post to /my/language and change their language.
class PreferencesController(http.Controller):
@http.route("/my/language", type="http", auth="user", methods=["POST"])
def set_language(self, lang):
request.env.user.write({"lang": lang})
return request.redirect("/my")
<form action="/my/language" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<select name="lang">...</select>
</form>