security: add module blocklist for YAML agent config code references#5821
security: add module blocklist for YAML agent config code references#5821Ashutosh0x wants to merge 1 commit into
Conversation
|
Response from ADK Triaging Agent Hello @Ashutosh0x, thank you for creating this PR! This is a great security hardening change. To help the reviewers and ensure alignment with our contribution guidelines, could you please update your PR description or add a comment to include:
This information will help reviewers to review your PR more efficiently. Thanks! |
|
Hi @adk-bot! Here are the test results as requested. Security Validation ResultsAll 5 security tests pass — blocked modules are correctly rejected, and legitimate google.adk modules continue to work: ` === Test 2: subprocess.Popen blocked === === Test 3: builtins.exec blocked === === Test 4: pickle.loads blocked === === Test 5: google.adk.agents.llm_agent.LlmAgent allowed === All security tests completed. Test CoverageThe PR includes 7 new parameterized test functions in
All tests use Happy to address any further feedback! 🙏 |
|
Pushed two follow-up commits based on @surajksharma07's review:
All
Ready for maintainer review when convenient. |
363e48f to
fba8ff2
Compare
|
Hi @surajksharma07 — I've addressed your review feedback in the latest commits. The module blocklist is now gated via _validate_module_reference() before importlib.import_module(). All 5 security tests pass. Ready for re-review when you get a chance. Thanks! |
|
Hi @Ashutosh0x , Thank you for your contribution! We appreciate you taking the time to submit this pull request. Please fix the failing tests before we can proceed with the review. |
567807a to
2c73ecd
Compare
|
Hi @rohityan -- the failing tests have been fixed in the latest push (commit 2c73ecd). All CI checks are green now (CLA, Actions Scan, header-check). All 16 security test cases pass, and every importlib.import_module() call site in config_agent_utils.py is gated by the module blocklist validation. cc @seanzhougoogle @sasha-gitg @GWeale -- this is a security hardening PR, would appreciate a maintainer review when you get a chance. Happy to address any feedback. Thanks. |
|
Hi @Ashutosh0x , could you please resolve the conflicts. |
2c73ecd to
8cebb64
Compare
|
Hi @rohityan — conflicts resolved in the latest force-push (commit 8cebb64). The branch is now rebased cleanly on top of main. Changes in this rebase:
Ready for re-review when convenient. Thanks! |
8cebb64 to
c0b4bc2
Compare
|
Hi @rohityan — just rebased this branch onto latest main so it's no longer behind. All CI checks are passing. This fixes the arbitrary module import vulnerability in The fix adds a configurable allowlist of permitted module prefixes so only explicitly approved packages can be loaded as callbacks. Let me know if you'd like any changes! |
c0b4bc2 to
18c27fe
Compare
|
I am going to read the Executive Summary
Detailed Findings & Analysis1. Objectives & Impact ("What does it do?")
2. Justification & Value ("Is it a valid and useful change?")
3. Principle & Style Alignment Checklist ("Does it follow rules?")
Summary of Work Done
|
- Enable _ENFORCE_DENYLIST by default (True) so the blocklist is active
out of the box, not opt-in.
- Expand _BLOCKED_MODULES from 27 to 36 entries, adding network-capable
stdlib modules (ftplib, smtplib, poplib, imaplib, nntplib, telnetlib,
xmlrpc, asyncio) and filesystem modules (pathlib) that were identified
as gaps during review.
- Gate _resolve_tools() in LlmAgent (llm_agent.py L1047) with
_validate_module_reference() before importlib.import_module().
This was the last ungated import site: a YAML config with
tools: [{name: os.system}] would previously import the os module
without restriction.
- Organise _BLOCKED_MODULES by category (process/OS, code eval,
native/unsafe, network, filesystem/serialisation, interactive).
- Add comprehensive tests:
* _resolve_tools() blocks dangerous modules (os, subprocess, builtins,
pickle) and allows ADK built-in tools (no dot in name).
* Newly blocked network modules are rejected (ftplib, smtplib, xmlrpc,
telnetlib, poplib, imaplib, asyncio, pathlib).
* _set_enforce_denylist(False) escape hatch works.
Import sites gated (audit):
config_agent_utils.py: resolve_fully_qualified_name (L192),
_resolve_agent_code_reference (L246), resolve_code_reference (L274)
llm_agent.py: _resolve_tools user-defined path (L1049)
llm_agent.py: _resolve_tools built-in path (L1043) — N/A, hardcoded
to google.adk.tools
Fixes google#5822
18c27fe to
df75a3b
Compare
|
Hi @rohityan — rebased onto latest main, branch is now up-to-date. All 52 tests pass, CI is green. Changes since last review:
Ready for review. 🙏 |
|
I have analyzed Pull Request #5821 in detail and generated a comprehensive ADK Pull Request Analysis Report in accordance with the repository's architectural guidelines and security standards. The complete structured findings are available in the persistent artifact file: Key Takeaways & Recommendations
Key Decisions for Reviewers
|
|
@rohityan All CI checks pass, adk-bot recommends approve, branch is up-to-date — ready for your review and merge when convenient. |
Fixes #5822
Summary
This PR adds a module blocklist to prevent importing dangerous standard library modules via YAML agent configurations. It is a defense-in-depth hardening that complements the existing args key block from the CVE-2026-4810 fix.
Problem
The CVE-2026-4810 fix blocked the
argskey in YAML configs to prevent passing arguments to constructors. However, the following functions still callimportlib.import_module()with no restriction on which modules can be imported:resolve_code_reference()— used for callbacks, schemas, model_coderesolve_fully_qualified_name()— used for agent class resolution_resolve_tools()— used for user-defined tool resolution_resolve_agent_code_reference()— used for agent code referencesExample malicious YAML (currently accepted):
Solution
1. Module blocklist with 36 dangerous stdlib modules
Added
_BLOCKED_MODULESfrozenset organized by category:os,subprocess,sys,builtins,importlib,shutil,signal,multiprocessing,threadingcode,codeop,compileall,runpyctypessocket,http,urllib,ftplib,smtplib,poplib,imaplib,nntplib,telnetlib,xmlrpc,asynciotempfile,pathlib,shelve,pickle,marshalwebbrowser,antigravity,pty,commands,pdb,profile2. Validation at ALL import sites
Added
_validate_module_reference()that checks the top-level module against the blocklist beforeimportlib.import_module()is called.resolve_fully_qualified_name()config_agent_utils.py_resolve_agent_code_reference()config_agent_utils.pyresolve_code_reference()config_agent_utils.py_resolve_tools()user-definedllm_agent.py_resolve_tools()built-inllm_agent.pygoogle.adk.tools)3. Enabled by default
_ENFORCE_DENYLIST = True— the blocklist is active by default, with_set_enforce_denylist(False)available as an escape hatch for operators who need custom modules.Files Changed
src/google/adk/agents/config_agent_utils.py(+83) —_BLOCKED_MODULES,_validate_module_reference(), validation calls at 3 import sites,_ENFORCE_DENYLIST = Truesrc/google/adk/agents/llm_agent.py(+3) — Validation gate in_resolve_tools()for user-defined toolstests/unittests/agents/test_agent_config.py(+115) — 8 new security test functionsTesting
All 52 tests pass (0 failures):
New security test coverage:
test_resolve_code_reference_blocks_os_when_enforcedos.systemblocked viaresolve_code_referencetest_resolve_fully_qualified_name_blocks_subprocess_when_enforcedsubprocess.Popenblocked (verifies wrapped cause)test_allowed_module_passes_when_enforcedgoogle.adk.*modules pass through (no false positives)test_resolve_agent_code_reference_blocks_when_enforced_resolve_agent_code_referencetest_resolve_tools_blocks_dangerous_modules_resolve_toolstest_resolve_tools_allows_builtin_adk_toolsgoogle_search(built-in, no dot) passes throughtest_newly_blocked_network_modules_are_rejectedtest_denylist_can_be_disabled_set_enforce_denylist(False)escape hatch worksAll existing tests remain unchanged and passing. Zero risk of regression.