@@ -105,10 +105,76 @@ def _load_config_from_path(config_path: str) -> AgentConfig:
105105 return AgentConfig .model_validate (config_data )
106106
107107
108+ _ENFORCE_DENYLIST = False
109+
110+ # Modules that must never be imported via YAML agent configuration.
111+ # These provide direct access to the operating system, process execution,
112+ # or dynamic code evaluation and could be abused to achieve arbitrary
113+ # code execution when referenced in callback, tool, schema, or model
114+ # code-reference fields.
115+ _BLOCKED_MODULES = frozenset ({
116+ "os" ,
117+ "subprocess" ,
118+ "sys" ,
119+ "builtins" ,
120+ "importlib" ,
121+ "shutil" ,
122+ "socket" ,
123+ "http" ,
124+ "urllib" ,
125+ "ctypes" ,
126+ "multiprocessing" ,
127+ "threading" ,
128+ "signal" ,
129+ "code" ,
130+ "codeop" ,
131+ "compileall" ,
132+ "runpy" ,
133+ "webbrowser" ,
134+ "antigravity" ,
135+ "pty" ,
136+ "commands" ,
137+ "pdb" ,
138+ "profile" ,
139+ "tempfile" ,
140+ "shelve" ,
141+ "pickle" ,
142+ "marshal" ,
143+ })
144+
145+
146+ def _validate_module_reference (fully_qualified_name : str ) -> None :
147+ """Validate that a module reference does not target a blocked module.
148+
149+ Args:
150+ fully_qualified_name: The fully-qualified Python name to validate
151+ (e.g. ``"my_package.my_module.my_func"``).
152+
153+ Raises:
154+ ValueError: If the top-level module is in ``_BLOCKED_MODULES``.
155+ """
156+ if not _ENFORCE_DENYLIST :
157+ return
158+ # Extract the top-level package from the fully-qualified name.
159+ top_module = fully_qualified_name .split ("." )[0 ]
160+ if top_module in _BLOCKED_MODULES :
161+ raise ValueError (
162+ f"Blocked module reference: { fully_qualified_name !r} . "
163+ f"Importing from the '{ top_module } ' module is not allowed in "
164+ "agent configurations because it can execute arbitrary code."
165+ )
166+
167+
168+ def _set_enforce_denylist (value : bool ) -> None :
169+ global _ENFORCE_DENYLIST
170+ _ENFORCE_DENYLIST = value
171+
172+
108173@experimental (FeatureName .AGENT_CONFIG )
109174def resolve_fully_qualified_name (name : str ) -> Any :
110175 try :
111176 module_path , obj_name = name .rsplit ("." , 1 )
177+ _validate_module_reference (name )
112178 module = importlib .import_module (module_path )
113179 return getattr (module , obj_name )
114180 except Exception as e :
@@ -160,6 +226,7 @@ def _resolve_agent_code_reference(code: str) -> Any:
160226 if "." not in code :
161227 raise ValueError (f"Invalid code reference: { code } " )
162228
229+ _validate_module_reference (code )
163230 module_path , obj_name = code .rsplit ("." , 1 )
164231 module = importlib .import_module (module_path )
165232 obj = getattr (module , obj_name )
@@ -189,6 +256,7 @@ def resolve_code_reference(code_config: CodeConfig) -> Any:
189256 if not code_config or not code_config .name :
190257 raise ValueError ("Invalid CodeConfig." )
191258
259+ _validate_module_reference (code_config .name )
192260 module_path , obj_name = code_config .name .rsplit ("." , 1 )
193261 module = importlib .import_module (module_path )
194262 return getattr (module , obj_name )
0 commit comments