Skip to content

OD702 code-injection-flow

Data a user controls reaches safe_eval(), eval() or exec().

Category Severity Series Needs the index
Security Error all no

What it reports

A value from a source that reaches the first argument of safe_eval(), eval() or exec(), directly or through formatting, locals and the methods it is passed to.

Why it matters

The expression is code, and the user writes it. eval() and exec() run it as the server process, with access to everything Python can reach. safe_eval() refuses imports and private attributes, but the expression still runs with every value of its context, such as env or records, and with the rights of the code that calls it; its sandbox has been escaped before. Expressions belong in records only administrators edit, such as server actions. Input that holds data is parsed as data, with json.loads() or ast.literal_eval(), or chosen from a fixed set.

Example

controllers/main.py
class PriceController(http.Controller):
    @http.route("/shop/price", type="json", auth="user")
    def price(self, formula, amount):
        return safe_eval(formula, {"amount": amount})

Any signed-in user can send any expression as formula.

controllers/main.py
FORMULAS = {
    "net": lambda amount: amount,
    "gross": lambda amount: amount * 1.21,
}


class PriceController(http.Controller):
    @http.route("/shop/price", type="json", auth="user")
    def price(self, formula, amount):
        return FORMULAS[formula](float(amount))

Suppressing

return safe_eval(formula, context)  # odooscan: ignore[OD702]

See suppressing a finding.