馃敶 Required Information
Is your feature request related to a specific problem?
Yes.
adk web enables a recursive denylist that rejects every YAML key named args.
This is an important defense-in-depth mitigation for CVE-2026-4810: a generic tool configuration can combine a Python code reference in name with attacker-controlled args, causing ADK to import and invoke arbitrary Python code (74f235b).
However, the key-level denylist also rejects built-in tools whose arguments are declarative configuration.
In particular, the existing McpToolset YAML sample cannot be loaded by adk web:
name: retrospective_master
instruction: Use the MCP tools.
model: gemini-3.7-flash
tools:
- name: McpToolset
args:
streamable_http_connection_params:
url: https://hurikaeri-site.viva-tweet-x.workers.dev/mcp
The same agent works when constructed in Python or loaded by adk run.
Under adk web, the local YAML agent fails to load and is absent from the agent loader, so a subsequent POST /run_sse returns 404 Not Found.
|
_BLOCKED_YAML_KEYS = frozenset({"args"}) |
|
if key in _BLOCKED_YAML_KEYS: |
|
raise ValueError( |
|
f"Blocked key {key!r} found in {filename!r}. " |
|
f"The '{key}' field is not allowed in agent configurations " |
|
"because it can execute arbitrary code." |
|
) |
Describe the Solution You'd Like
Replace the all-or-nothing key check for locally loaded YAML with a positive allowlist for security-reviewed ADK built-ins.
For an allowlisted built-in such as the exact literal name McpToolset:
- Do not resolve a module name supplied by YAML.
- Validate
args with a fixed ADK-owned Pydantic schema.
- Reject values that cannot be represented by that schema, including config-supplied callable fields.
- Construct the fixed ADK-owned tool class through its normal
from_config() implementation.
- Continue rejecting
args for user-defined tools, factories, custom agents, callbacks, and every unregistered built-in.
- Preserve the existing default rejection of config-supplied stdio MCP servers unless
ADK_ALLOW_CONFIG_STDIO_MCP_SERVERS=1 is explicitly set.
This proposal applies only to configurations loaded from the local agents directory.
Agent Builder uploads should continue rejecting every args key until ADK has a separate policy for config-supplied remote MCP URLs and SSRF.
Impact on your work
This restores the ability to define an McpToolset in a local root_agent.yaml and use the agent from the ADK Web chat UI, without reopening the generic name plus args arbitrary-code-execution path.
It also makes the existing config-based MCP sample consistent with adk web when the documented stdio opt-in is enabled.
Willingness to contribute
Yes.
馃煛 Recommended Information
Describe Alternatives You've Considered
-
Keep rejecting every args key.
This closes the reported RCE path but prevents declarative configuration for McpToolset and other reviewed built-ins.
-
Add more blocked Python modules.
Module denylists are useful defense in depth, but do not provide a safe path for restoring declarative built-in configuration.
Alias modules and future Python releases also require continuing denylist maintenance.
-
Allow args whenever name appears to reference McpToolset.
This is too broad if arbitrary qualified names or custom agent schemas can opt into the exception.
Matching must be limited to the typed LlmAgent.tools position and an exact, statically registered built-in name.
-
Permit the same exception in Agent Builder uploads.
This would also allow uploaded YAML to select remote MCP URLs.
That requires a separate SSRF policy, such as allowed origins or operator-controlled server references, and is intentionally excluded from the initial change.
-
Require Python-based agent definitions.
This is a valid workaround, but makes the checked-in YAML MCP sample
unusable with the ADK Web chat UI.
Proposed API / Implementation
The user-facing YAML retains its existing shape:
name: mcp_agent
model: gemini-3.7-flash
instruction: Use the MCP tools.
tools:
- name: McpToolset
args:
streamable_http_connection_params:
url: https://example.com/mcp
Conceptually, validation uses a static registry:
SAFE_BUILTIN_TOOL_ARGS_VALIDATORS = {
"McpToolset": validate_mcp_toolset_args,
}
validator = SAFE_BUILTIN_TOOL_ARGS_VALIDATORS.get(tool.name)
if validator is not None:
validator(tool.args)
return construct_registered_builtin(tool.name, tool.args)
reject_args()
The registry key is matched literally and is never passed to importlib.import_module().
For stdio configurations, the existing ADK_ALLOW_CONFIG_STDIO_MCP_SERVERS=1 operator opt-in remains required.
The exception applies only when args appears on a registered tool under the tools field of a built-in LlmAgent.
A custom agent containing a lookalike tools field does not receive the exception.
Acceptance Criteria
- A local
root_agent.yaml containing valid registered McpToolset.args loads under adk web.
- A remote HTTP McpToolset can be constructed without importing a YAML-supplied module.
- A stdio McpToolset remains rejected by default.
- A stdio McpToolset loads only after the existing explicit operator opt-in.
args on user-defined tools and factories remains rejected.
- A callable field such as
httpx_client_factory: os.system is rejected.
- A custom agent containing a lookalike
tools field cannot opt into the exception.
- Agent Builder uploads continue rejecting every
args key.
- Existing module-reference and project-boundary checks continue to pass.
Additional Context
Related security work:
馃敶 Required Information
Is your feature request related to a specific problem?
Yes.
adk webenables a recursive denylist that rejects every YAML key namedargs.This is an important defense-in-depth mitigation for CVE-2026-4810: a generic tool configuration can combine a Python code reference in
namewith attacker-controlledargs, causing ADK to import and invoke arbitrary Python code (74f235b).However, the key-level denylist also rejects built-in tools whose arguments are declarative configuration.
In particular, the existing
McpToolsetYAML sample cannot be loaded byadk web:The same agent works when constructed in Python or loaded by
adk run.Under
adk web, the local YAML agent fails to load and is absent from the agent loader, so a subsequentPOST /run_ssereturns404 Not Found.adk-python/src/google/adk/agents/config_agent_utils.py
Line 86 in 25e8ea6
adk-python/src/google/adk/agents/config_agent_utils.py
Lines 99 to 104 in 25e8ea6
Describe the Solution You'd Like
Replace the all-or-nothing key check for locally loaded YAML with a positive allowlist for security-reviewed ADK built-ins.
For an allowlisted built-in such as the exact literal name
McpToolset:argswith a fixed ADK-owned Pydantic schema.from_config()implementation.argsfor user-defined tools, factories, custom agents, callbacks, and every unregistered built-in.ADK_ALLOW_CONFIG_STDIO_MCP_SERVERS=1is explicitly set.This proposal applies only to configurations loaded from the local agents directory.
Agent Builder uploads should continue rejecting every
argskey until ADK has a separate policy for config-supplied remote MCP URLs and SSRF.Impact on your work
This restores the ability to define an
McpToolsetin a localroot_agent.yamland use the agent from the ADK Web chat UI, without reopening the genericnameplusargsarbitrary-code-execution path.It also makes the existing config-based MCP sample consistent with
adk webwhen the documented stdio opt-in is enabled.Willingness to contribute
Yes.
馃煛 Recommended Information
Describe Alternatives You've Considered
Keep rejecting every
argskey.This closes the reported RCE path but prevents declarative configuration for
McpToolsetand other reviewed built-ins.Add more blocked Python modules.
Module denylists are useful defense in depth, but do not provide a safe path for restoring declarative built-in configuration.
Alias modules and future Python releases also require continuing denylist maintenance.
Allow
argswhenevernameappears to referenceMcpToolset.This is too broad if arbitrary qualified names or custom agent schemas can opt into the exception.
Matching must be limited to the typed
LlmAgent.toolsposition and an exact, statically registered built-in name.Permit the same exception in Agent Builder uploads.
This would also allow uploaded YAML to select remote MCP URLs.
That requires a separate SSRF policy, such as allowed origins or operator-controlled server references, and is intentionally excluded from the initial change.
Require Python-based agent definitions.
This is a valid workaround, but makes the checked-in YAML MCP sample
unusable with the ADK Web chat UI.
Proposed API / Implementation
The user-facing YAML retains its existing shape:
Conceptually, validation uses a static registry:
The registry key is matched literally and is never passed to
importlib.import_module().For stdio configurations, the existing
ADK_ALLOW_CONFIG_STDIO_MCP_SERVERS=1operator opt-in remains required.The exception applies only when
argsappears on a registered tool under thetoolsfield of a built-inLlmAgent.A custom agent containing a lookalike
toolsfield does not receive the exception.Acceptance Criteria
root_agent.yamlcontaining valid registeredMcpToolset.argsloads underadk web.argson user-defined tools and factories remains rejected.httpx_client_factory: os.systemis rejected.toolsfield cannot opt into the exception.argskey.Additional Context
Related security work: