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¶
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.
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")