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