python-kwargs-setattr-security
by microsoft
When reviewing or fixing Python code that uses setattr() with user-controlled kwargs to configure C++ extension objects (SessionOptions, RunOptions, etc.) in…
npx skills add https://github.com/microsoft/onnxruntime --skill python-kwargs-setattr-securityProblem Pattern
Using hasattr(obj, k) / setattr(obj, k, v) with user-controlled kwargs is insecure. The hasattr check is NOT a security guard — it returns True for ALL exposed properties including dangerous ones.
# INSECURE — do not use
for k, v in kwargs.items():
if hasattr(options, k):
setattr(options, k, v)
Fix: Explicit Allowlist
Define a module-level frozenset of safe attribute names. Raise RuntimeError for known-but-blocked attrs; silently ignore unknown keys.
# Define at module level, before the class
_ALLOWED_SESSION_OPTIONS = frozenset({
"enable_cpu_mem_arena",
"enable_mem_pattern",
# ... only explicitly reviewed safe attrs
})
# In the method
for k, v in kwargs.items():
if k in _ALLOWED_SESSION_OPTIONS:
setattr(options, k, v)
elif hasattr(options, k): # reuse the existing instance, don't create new
raise RuntimeError(
f"SessionOptions attribute '{k}' is not permitted via the backend API. "
f"Allowed attributes: {', '.join(sorted(_ALLOWED_SESSION_OPTIONS))}"
)
# else: silently ignore (may be kwargs for a different config object)
Key Rules
- Use the existing object in
hasattr(options, k)— neverhasattr(ClassName(), k)(creates throwaway C++ objects per iteration) - RuntimeError is the ORT convention for API misuse errors (not ValueError)
- Silent ignore for one path is OK when kwargs are forwarded to both paths:
run_model()passes the same kwargs dict to bothprepare()(validates SessionOptions) andrep.run()(validates RunOptions). A RunOptions kwarg unknown to SessionOptions is silently ignored byprepare()— this is correct becauserep.run()will validate it. Only raise RuntimeError when the attr exists on the target object but is blocked. - Frozenset constant naming:
_ALLOWED_<CLASSNAME>— ALL_CAPS, Google Style - No type annotations on module-level constants (ORT Python convention)
Dangerous SessionOptions Properties (never allowlist)
optimized_model_filepath— triggers Model::Save(), overwrites arbitrary filesprofile_file_prefix+enable_profiling— writes profiling JSON to arbitrary pathregister_custom_ops_library— loads arbitrary shared libraries (method, not property)
Files in ONNX Runtime
onnxruntime/python/backend/backend.py—_ALLOWED_SESSION_OPTIONSonnxruntime/python/backend/backend_rep.py—_ALLOWED_RUN_OPTIONS- Tests:
onnxruntime/test/python/onnxruntime_test_python_backend.py—TestBackendKwargsAllowlist