Avoid shell execution in ReadFileTool ranged reads - #5268
Closed
petrmarinec wants to merge 1 commit into
Closed
Conversation
Collaborator
|
Hi @petrmarinec , Thank you for your contribution! We appreciate you taking the time to submit this pull request. Your PR has been received by the team and is currently under review. We will provide feedback as soon as we have an update to share. |
Collaborator
|
Hi @wukath , can you please review this. |
Collaborator
|
Hi @petrmarinec , can you please resolve the branch conflicts. |
petrmarinec
force-pushed
the
fix-readfile-shell-injection
branch
from
May 12, 2026 11:14
5df3e52 to
38d8b80
Compare
Contributor
Author
Hi! done. |
petrmarinec
force-pushed
the
fix-readfile-shell-injection
branch
from
June 10, 2026 09:04
38d8b80 to
34b7c30
Compare
petrmarinec
force-pushed
the
fix-readfile-shell-injection
branch
from
June 17, 2026 23:23
34b7c30 to
af7289e
Compare
Contributor
Author
copybara-service Bot
pushed a commit
that referenced
this pull request
Jul 8, 2026
Merge #5268 ### Link to Issue or Description of Change **1. Link to an existing issue (if applicable):** - Related: #5267 **2. Or, if no issue exists, describe the change:** **Problem:** `ReadFileTool` handles ranged reads by building `cat -n '{path}' | sed -n ...` from the caller-supplied `path`, while full reads use `environment.read_file(path)` and Python slicing. Shell metacharacters in `path` are therefore interpreted by the shell in the ranged-read branch instead of being treated as a literal file path. **Solution:** Remove the shell-based ranged-read branch and reuse the existing Python file-read logic for all reads. This keeps ranged output behavior while eliminating the shell dependency from `ReadFileTool`. ### Testing Plan **Unit Tests:** - [x] I have added or updated unit tests for my change. - [ ] All unit tests pass locally. Passed locally in Linux Docker (`python:3.11-bookworm`): - `pytest tests/unittests/tools/test_environment_tools.py tests/unittests/tools/environment_simulation` - `pytest tests/unittests/tools` - Result: `1519 passed` **Manual End-to-End (E2E) Tests:** - [x] On unmodified `origin/main`, a ranged `ReadFileTool` call with a crafted path wrote a proof file in the working directory. - [x] After this patch, the same call returns `File not found: ...` and no proof file is written. ### Checklist - [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document. - [x] I have performed a self-review of my own code. - [ ] I have commented my code, particularly in hard-to-understand areas. - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] New and existing unit tests pass locally with my changes. - [x] I have manually tested my changes end-to-end. - [x] Any dependent changes have been merged and published in downstream modules. ### Additional context This is a small fix that removes the shell-based ranged-read implementation and makes `ReadFileTool` use the same direct file-read path for both full reads and ranged reads. Co-authored-by: Shangjie Chen <deanchen@google.com> COPYBARA_INTEGRATE_REVIEW=#5268 from petrmarinec:fix-readfile-shell-injection 34b7c30 PiperOrigin-RevId: 944768002
Collaborator
|
Thank you @petrmarinec for your contribution! 🎉 Your changes have been successfully imported and merged via Copybara in commit 1ac6875. Closing this PR as the changes are now in the main branch. |
Contributor
Author
|
For attribution: this merged fix corresponds to Google OSS VRP report #497794205: |
sasha-gitg
added a commit
to sasha-gitg/adk-python-public
that referenced
this pull request
Aug 5, 2026
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.
FrigaZzz
pushed a commit
to FrigaZzz/adk-python
that referenced
this pull request
Aug 11, 2026
Merge google#5268 ### Link to Issue or Description of Change **1. Link to an existing issue (if applicable):** - Related: google#5267 **2. Or, if no issue exists, describe the change:** **Problem:** `ReadFileTool` handles ranged reads by building `cat -n '{path}' | sed -n ...` from the caller-supplied `path`, while full reads use `environment.read_file(path)` and Python slicing. Shell metacharacters in `path` are therefore interpreted by the shell in the ranged-read branch instead of being treated as a literal file path. **Solution:** Remove the shell-based ranged-read branch and reuse the existing Python file-read logic for all reads. This keeps ranged output behavior while eliminating the shell dependency from `ReadFileTool`. ### Testing Plan **Unit Tests:** - [x] I have added or updated unit tests for my change. - [ ] All unit tests pass locally. Passed locally in Linux Docker (`python:3.11-bookworm`): - `pytest tests/unittests/tools/test_environment_tools.py tests/unittests/tools/environment_simulation` - `pytest tests/unittests/tools` - Result: `1519 passed` **Manual End-to-End (E2E) Tests:** - [x] On unmodified `origin/main`, a ranged `ReadFileTool` call with a crafted path wrote a proof file in the working directory. - [x] After this patch, the same call returns `File not found: ...` and no proof file is written. ### Checklist - [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document. - [x] I have performed a self-review of my own code. - [ ] I have commented my code, particularly in hard-to-understand areas. - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] New and existing unit tests pass locally with my changes. - [x] I have manually tested my changes end-to-end. - [x] Any dependent changes have been merged and published in downstream modules. ### Additional context This is a small fix that removes the shell-based ranged-read implementation and makes `ReadFileTool` use the same direct file-read path for both full reads and ranged reads. Co-authored-by: Shangjie Chen <deanchen@google.com> COPYBARA_INTEGRATE_REVIEW=google#5268 from petrmarinec:fix-readfile-shell-injection 34b7c30 PiperOrigin-RevId: 944768002
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to Issue or Description of Change
1. Link to an existing issue (if applicable):
2. Or, if no issue exists, describe the change:
Problem:
ReadFileToolhandles ranged reads by buildingcat -n '{path}' | sed -n ...from the caller-suppliedpath, while full reads useenvironment.read_file(path)and Python slicing. Shell metacharacters inpathare therefore interpreted by the shell in the ranged-read branch instead of being treated as a literal file path.Solution:
Remove the shell-based ranged-read branch and reuse the existing Python file-read logic for all reads. This keeps ranged output behavior while eliminating the shell dependency from
ReadFileTool.Testing Plan
Unit Tests:
Passed locally in Linux Docker (
python:3.11-bookworm):pytest tests/unittests/tools/test_environment_tools.py tests/unittests/tools/environment_simulationpytest tests/unittests/tools1519 passedManual End-to-End (E2E) Tests:
origin/main, a rangedReadFileToolcall with a crafted path wrote a proof file in the working directory.File not found: ...and no proof file is written.Checklist
Additional context
This is a small fix that removes the shell-based ranged-read implementation and makes
ReadFileTooluse the same direct file-read path for both full reads and ranged reads.