Describe the bug
safe_eval(..., rewrite_np=True) is intended to wrap int/float literals in numpy types (e.g. np.int32) to prevent denial-of-service via slow native-Python exponentiation. Two bugs make this protection completely ineffective:
_RewriteConstNp.visit_Constant calls ast.parse(...) which returns an ast.Module node, but visit_Constant must return an ast.expr node. This corrupts the AST tree.
safe_eval evaluates the original string (eval(expr, ...)) instead of the rewritten AST, so the numpy-wrapping is silently discarded.
Additionally, the docstring on line 77 has a typo: "expressoini" should be "expression".
To Reproduce
import numpy as np
from monai.utils import safe_eval
# rewrite_np should produce numpy types, but returns native Python types
result = safe_eval("2 + 3", rewrite_np=True)
print(type(result)) # <class 'int'> — expected np.int32
# DoS protection is ineffective: this hangs under native Python int
# but should overflow instantly under np.int32
result = safe_eval("9**9**9", rewrite_np=True)
print(type(result)) # <class 'int'> — expected np.int32
Expected behavior
With rewrite_np=True, all int/float literals should be wrapped in the specified numpy types and the rewritten AST should be evaluated. safe_eval("2 + 3", rewrite_np=True) should return np.int32(5), not Python int(5).
Environment
MONAI version: 1.6.0rc1+53.g43c0aaed (includes PR #8936)
Additional context
Introduced in #8936. The existing tests pass because they only check numerical equality (assertEqual), not that the result type is actually numpy.
The call site in monai/bundle/scripts.py:168 relies on rewrite_np=True to prevent DoS attacks via bundle config expressions, so this is a security gap.
I have a fix and regression tests ready — opening a PR shortly.
Describe the bug
safe_eval(..., rewrite_np=True)is intended to wrap int/float literals in numpy types (e.g.np.int32) to prevent denial-of-service via slow native-Python exponentiation. Two bugs make this protection completely ineffective:_RewriteConstNp.visit_Constantcallsast.parse(...)which returns anast.Modulenode, butvisit_Constantmust return anast.exprnode. This corrupts the AST tree.safe_evalevaluates the original string (eval(expr, ...)) instead of the rewritten AST, so the numpy-wrapping is silently discarded.Additionally, the docstring on line 77 has a typo: "expressoini" should be "expression".
To Reproduce
Expected behavior
With
rewrite_np=True, all int/float literals should be wrapped in the specified numpy types and the rewritten AST should be evaluated.safe_eval("2 + 3", rewrite_np=True)should returnnp.int32(5), not Pythonint(5).Environment
Additional context
Introduced in #8936. The existing tests pass because they only check numerical equality (
assertEqual), not that the result type is actually numpy.The call site in
monai/bundle/scripts.py:168relies onrewrite_np=Trueto prevent DoS attacks via bundle config expressions, so this is a security gap.I have a fix and regression tests ready — opening a PR shortly.