Skip to content

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

controllers/main.py
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.

controllers/main.py
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")
views/templates.xml
<form action="/my/language" method="post">
    <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
    <select name="lang">...</select>
</form>

Suppressing

@http.route("/shipping/webhook", type="http", auth="public", csrf=False)  # odooscan: ignore[OD112]

See suppressing a finding.