Skip to content

safe_eval rewrite_np does not actually wrap constants in numpy types #9062

Description

@chhayankjain

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:

  1. _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.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions