Skip to content

agents: block all stdlib modules in agent-config code-refs (denylist bypass via cProfile.run/timeit) - #6596

Open
asroyxCySec wants to merge 1 commit into
google:mainfrom
asroyxCySec:fix/agent-config-stdlib-denylist-bypass
Open

agents: block all stdlib modules in agent-config code-refs (denylist bypass via cProfile.run/timeit)#6596
asroyxCySec wants to merge 1 commit into
google:mainfrom
asroyxCySec:fix/agent-config-stdlib-denylist-bypass

Conversation

@asroyxCySec

Copy link
Copy Markdown

Problem

config_agent_utils._validate_module_reference() protects YAML agent configs against arbitrary code execution by blocking a hand-maintained denylist of dangerous stdlib modules (_BLOCKED_MODULES) referenced in tool / callback / model / schema code-refs. The check only compares the top-level module name against the denylist.

A top-level-name denylist is inherently incomplete: equivalent code-execution gadgets that are not in the list slip through. The clearest example is already visible in the current list — profile is blocked (its profile.run("<code>") executes arbitrary code), but its C sibling cProfile is not, and cProfile.run("<code>") is the identical gadget. Other reachable, non-listed gadgets include timeit.timeit("<code>"), pydoc, logging.config.fileConfig, bdb, trace, and venv.

Example bypass (before this change):

from google.adk.agents import config_agent_utils
# passes validation, then resolves to a callable that runs arbitrary code:
run = config_agent_utils.resolve_fully_qualified_name("cProfile.run")
run("open('/tmp/pwned','w').write('rce')")

Fix

Agent-config code-refs point to user-defined or ADK packages, never to the Python standard library. So instead of chasing individual gadgets, reject any standard-library top-level module via sys.stdlib_module_names (Python 3.10+, which matches the project's requires-python). The existing _BLOCKED_MODULES set is kept as documentation / belt-and-suspenders. Legitimate references (user packages, google.adk.*) are unaffected because they are not part of sys.stdlib_module_names.

Testing

  • New parametrized regression test test_stdlib_gadget_modules_are_rejected covers the previously-bypassing gadgets (cProfile.run, timeit.timeit, pydoc, logging.config.fileConfig, bdb, trace, venv).
  • New test_non_stdlib_references_are_not_blocked confirms user/ADK references still validate.
  • Existing blocked-module tests (os, subprocess, network modules, denylist-disable) continue to pass.
  • Verified the patched _validate_module_reference directly: all listed gadgets + the existing denylist entries are rejected, while my_company_pkg.my_tool and google.adk.tools.google_search are allowed.

The agent-config denylist (`_BLOCKED_MODULES`) only compared the top-level
module name of a code-ref against a hand-maintained list of dangerous stdlib
modules. That list is inherently incomplete: equivalent code-execution gadgets
slip through. For example `profile` is blocked (its `profile.run("<code>")`
runs arbitrary code) but its C sibling `cProfile` is not, and
`cProfile.run("<code>")` is the identical gadget. `timeit.timeit`, `pydoc`,
`logging.config.fileConfig`, `bdb`, `trace` and `venv` are similarly reachable.

Agent-config tool/callback/model/schema references point to user-defined or ADK
packages, never to the standard library, so reject any stdlib top-level module
via `sys.stdlib_module_names` (Python 3.10+, matching requires-python). This
closes the bypass class instead of chasing individual gadgets. `_BLOCKED_MODULES`
is kept for documentation/defense-in-depth; legitimate references (user
packages, `google.adk.*`) are unaffected.

Adds regression tests for the previously-bypassing gadgets and a test that
user/ADK references still validate.
@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants