OD111 public-route-sudo¶
A public or auth='none' route escalates with sudo().
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Security | Info | all | no |
What it reports¶
A controller method whose @http.route sets auth="public" or auth="none" and whose body calls
sudo(). This is a hotspot: code to review, not a confirmed flaw.
Why it matters¶
A public route answers anyone, signed in or not; auth="none" runs without any user. sudo()
lifts access rights and record rules, so from that point the code alone decides what the visitor
may read or change. When a record id, a domain or values come from the URL or the form, the route
must check that the visitor is entitled to that record, for example with an access token, or anyone
can walk through the ids and read or modify every record. Many public routes use sudo()
correctly; the finding asks for that check to be confirmed.
Routes with auth="user", the default, are not reported: Odoo's access rights still apply to the
signed-in user until the code calls sudo(). Only the route's own body is read, so a sudo() in
a helper it calls is not reported.
Example¶
class WarrantyController(http.Controller):
@http.route("/warranty/<int:claim_id>", type="http", auth="public", website=True)
def warranty_claim(self, claim_id):
claim = request.env["warranty.claim"].sudo().browse(claim_id)
return request.render("warranty_portal.claim_page", {"claim": claim})
Any visitor can open /warranty/1, /warranty/2 and so on and read every claim.
from odoo.addons.portal.controllers.portal import CustomerPortal
class WarrantyController(CustomerPortal):
@http.route("/warranty/<int:claim_id>", type="http", auth="public", website=True)
def warranty_claim(self, claim_id, access_token=None):
try:
claim = self._document_check_access("warranty.claim", claim_id, access_token)
except (AccessError, MissingError):
return request.redirect("/my")
return request.render("warranty_portal.claim_page", {"claim": claim})
With warranty.claim inheriting portal.mixin, the portal checks the visitor's access or the
record's token before it returns the record.