Skip to content

OD704 sudo-mass-assignment

A mapping a user controls is written as superuser, so the user picks the fields.

Category Severity Series Needs the index
Security Error all no

What it reports

A call to create() or write() on records under sudo() (env["x"].sudo(), a local assigned from it, or records browsed or searched from it) whose values are a mapping the user filled, keys included: the **kwargs of a route, request.params, a JSON body, the argument of a public model method, or a copy of one (dict(post), post.copy(), {**post}, vals.update(post)). See sources.

A dict whose keys the code writes, a comprehension that keeps only allowed keys, and a mapping checked by if any(key not in allowed for key in post): raise are not reported.

Why it matters

sudo() lifts access rights, record rules and field groups. A form that shows three fields still posts whatever the visitor adds to it, and every key becomes a field written as superuser: a relation to another company's records, a flag only managers set, or the fields that grant access. The values the form shows are the only ones to copy.

Example

controllers/main.py
class NewsletterController(http.Controller):
    @http.route("/newsletter/subscribe", type="http", auth="public", methods=["POST"], website=True)
    def subscribe(self, **post):
        request.env["mailing.contact"].sudo().create(post)
        return request.redirect("/newsletter/thanks")

A visitor who adds list_ids or company_id to the form sets them too.

controllers/main.py
class NewsletterController(http.Controller):
    @http.route("/newsletter/subscribe", type="http", auth="public", methods=["POST"], website=True)
    def subscribe(self, **post):
        request.env["mailing.contact"].sudo().create({
            "name": post.get("name"),
            "email": post.get("email"),
        })
        return request.redirect("/newsletter/thanks")

Suppressing

contact.sudo().write(values)  # odooscan: ignore[OD704]

See suppressing a finding.