-
Notifications
You must be signed in to change notification settings - Fork 3.4k
fix : ReadFileTool shells out on ranged reads and interpolates untrusted path #5537
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |
| from __future__ import annotations | ||
|
|
||
| import logging | ||
| import shlex | ||
| from typing import Any | ||
| from typing import Optional | ||
| from typing import TYPE_CHECKING | ||
|
|
@@ -187,7 +188,8 @@ async def run_async( | |
| sed_range = f'{start},{end_line}' | ||
| else: | ||
| sed_range = f'{start},$' | ||
| cmd = f"cat -n '{path}' | sed -n '{sed_range}p'" | ||
| safe_path = shlex.quote(path) | ||
| cmd = f"cat -n {safe_path} | sed -n '{sed_range}p'" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now if you replace the previous POC with the Updated POCimport asyncio
from pathlib import Path
import tempfile
from google.adk.environment._local_environment import LocalEnvironment
from google.adk.tools.environment._tools import ReadFileTool
async def main():
with tempfile.TemporaryDirectory() as td:
env = LocalEnvironment(working_dir=Path(td))
await env.initialize()
target = Path(td) / "sample.txt"
target.write_text("line1\nline2\nline3\n", encoding="utf-8")
marker = Path(td) / "marker.txt"
injected_end_line = f"1'; touch {marker}; echo '"
tool = ReadFileTool(env)
result = await tool.run_async(
args={"path": "sample.txt", "end_line": injected_end_line},
tool_context=None,
)
print(result)
# If this prints True, a file-read API caused an unintended side effect.
# That demonstrates the bug: the path was interpreted by the shell.
print("marker exists:", marker.exists())
await env.close()
asyncio.run(main())You could see that the current implementation of the file-read API could cause unintended side effects. #5558 is how I would fix it. |
||
| res = await self._environment.execute(cmd) | ||
| if res.exit_code == 0: | ||
| return {'status': 'ok', 'content': _truncate(res.stdout)} | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great, thanks! Can you add a few unit tests?