Skip to content

fix: avoid shell execution in ReadFileTool ranged reads and keep local environment file access in workspace - #6597

Merged
sasha-gitg merged 2 commits into
google:v1from
sasha-gitg:bp-505834257
Aug 5, 2026
Merged

fix: avoid shell execution in ReadFileTool ranged reads and keep local environment file access in workspace#6597
sasha-gitg merged 2 commits into
google:v1from
sasha-gitg:bp-505834257

Conversation

@sasha-gitg

Copy link
Copy Markdown
Collaborator

No description provided.

Backport of the following commits from `main`, released in v2.5.0:

  1ac6875
    fix: Avoid shell execution in ReadFileTool ranged reads (google#5268, relates to google#5267)
  3c0fb65
    fix(environment): add integer validation in ReadFileTool

Adapted rather than cherry-picked directly: on `main` these commits touch
`tools/environment/_read_file_tool.py`, which was split out of
`tools/environment/_tools.py` after the v1 branch point. The change is
applied here to `_tools.py`, where ReadFileTool still lives on v1.

`ReadFileTool` handled ranged reads by building
`cat -n '{path}' | sed -n '{range}p'` from the caller-supplied `path` and
passing it to `BaseEnvironment.execute()`, which runs the string through
`asyncio.create_subprocess_shell`. Full reads already used
`environment.read_file()` with Python slicing -- only the ranged branch
went through a shell. Shell metacharacters in `path` were therefore
interpreted by the shell instead of being treated as part of a literal
file path.

The shell branch is removed and all reads now use the existing
read-and-slice path. `start_line` / `end_line` are validated as non-bool
integers, since they now reach a Python slice directly instead of being
interpolated into a `sed` range.

Ranged-read output, line numbering and `total_lines` are unchanged.
@adk-bot adk-bot added the tools [Component] This issue is related to tools label Aug 5, 2026
Backport of the `_local_environment.py` / `test_local_environment.py`
portion of the following commit from `main`, released in v2.5.0:

  f41bc79
    (squashed copybara commit; upstream PR google#5870, fixes google#5869)

Only the two files above are taken from that commit -- the rest of it is
unrelated (a2a sample, PR-triage agent, transfer_to_agent_tool).

Adapted rather than cherry-picked directly: on `main` `_resolve_path`
returns a `Path`, while on v1 it returns `str` and `_sync_read` /
`_sync_write` take `str`. The containment check is the same; the v1
return type is preserved to keep the change minimal.

`_resolve_path` returned absolute paths verbatim:

    if os.path.isabs(path):
      return path

so `working_dir` was advisory only, and `read_file` / `write_file` --
and therefore the ReadFile, WriteFile and EditFile tools -- could reach
any path the process could access.

Paths are now resolved against `working_dir` and rejected with a
`ValueError` if they escape it. Absolute paths that stay inside
`working_dir` keep working.
@sasha-gitg
sasha-gitg merged commit c680728 into google:v1 Aug 5, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants