fix(configurable): prevent path traversal in AgentTool config_path resolution - #1407
fix(configurable): prevent path traversal in AgentTool config_path resolution#1407prasanna8585 wants to merge 1 commit into
Conversation
|
Hi @prasanna8585, thank you for your contribution! We truly appreciate for this fix. we have noticed that Your branch is currently out of sync with the main branch, and we heve encountered some issues with the Maven build. Could you please rebase your branch and resolve these build concerns so that we can move forward with the review process? |
916256d to
4d53afe
Compare
|
Hi @hemasekhar-p, thank you for the review. |
4d53afe to
ac172da
Compare
|
@prasanna8585 Thank you for the update. I noticed some inconsistencies in the code formatting now, could you please address those so we can proceed with the review? |
|
Hi @hemasekhar-p, thanks for catching that - pushed a formatting fix, should be consistent now. Let me know if anything else needs adjusting. |
|
@prasanna8585, could you please squash your commits into a single commit to keep the pull request history clean before we move forward with the review? |
…t directory resolveSubAgentFromConfigPath computed whether a sub-agent's config_path resolved outside the referencing agent's own directory, but only logged a warning and continued loading the target anyway. An absolute config_path was also accepted unconditionally. This meant an imported agent bundle -- ADK's own docs describe agent YAML configs as artifacts meant to be versioned and shared -- could reference a config_path such as ../../../.env or an absolute path and have the deploying application's own process read and attempt to load an arbitrary file outside the bundle's directory as a sub-agent. When the target file fails to parse as a valid agent config, ComponentRegistry.resolveAgentClass throws an IllegalArgumentException that embeds the raw parsed value verbatim. For a plain KEY=value style file (e.g. a .env), this reliably propagates the file's actual content into the exception chain, which the standard dev-server tooling (ConfigAgentLoader) logs via logger.error(...) -- so this is not just an unintended sub-agent load, but an arbitrary file content disclosure reachable through the standard 'adk web' workflow. Fix: reject an absolute config_path outright, and reject any relative config_path whose resolved, symlink-resolved target does not stay within the referencing agent's own directory -- matching the hard rejection adk-python (171ae9e) and adk-go (604dd63) already ship for the identical AgentTool config_path resolution. Adds regression tests covering relative traversal, absolute paths, and that a target file's content can no longer reach the exception chain.
0f0bf9e to
0abeca7
Compare
Summary
ConfigAgentUtils.resolveSubAgentFromConfigPath()accepted absoluteconfig_pathvalues unconditionally, and for relative values only logged a warning when the resolved path escaped the agent's own base directory -- it did not block the load:This is the same vulnerability class already hard-fixed with a breaking change in both other language ports:
adk-go: google/adk-go@604dd63 ("BREAKING: an absolute config_path is no longer accepted")adk-python: commit171ae9eThis port (issue #1218) had instead chosen a warn-only deprecation, leaving the traversal fully exploitable today: a
config_pathsuch as../../another_tenant/secret_agent.yamlor an absolute path is loaded and parsed as a full agent configuration, with only a log line noting the escape.Reachability
config_pathis a field in a subagent reference within an agent's own YAML config (sub_agents: - config_path: ...). In any deployment where different trust domains' agent configs are hosted under a shared root (e.g. a multi-tenant agent-hosting platform, or any scenario where config content can be influenced by a less-trusted party), this allows reading and loading arbitrary files reachable by the process as agent configuration -- outside the intended per-agent containment directory.Fix
config_pathvalues outright.toRealPath(), falling back to the lexical path when the target doesn't yet exist, so a missing file is still reported as not-found rather than misclassified as a traversal) -- matching the symlink-escape protection inadk-go's second commit for the same fix.Testing
fromConfig_subAgentConfigPathTraversal_throwsConfigurationException-- the exact../escape case, confirmed rejected.fromConfig_subAgentAbsoluteConfigPath_throwsConfigurationException-- the absolute-path case, confirmed rejected.fromConfig_withSubAgents_createsHierarchytest (a legitimate in-directory subagent reference) is unmodified and continues to pass, confirming no regression.Verification performed
Maven Central is not reachable in the environment I used to develop this fix, so I could not run
mvn testlocally. I instead dynamically confirmed both the vulnerability and the fix using a faithful, line-for-line transcription of the real method (standard JDK only, no external dependencies needed to exercise this specific logic):../secret_dir/victim_secret.yamlpath logged the deprecation warning, then proceeded to read the target file's full content regardless."Path traversal detected: ..."; an absolute path is rejected with"Absolute paths are not allowed..."; a legitimate in-directory reference still succeeds.