Required Information
Describe the Bug:
The load_skill_from_gcs_dir function in _utils.py extracts blob names from GCS and passes them to os.path.join() without sanitization. Because GCS allows blob names containing traversal sequences (e.g., skills/my_skill/../../../../tmp/malicious.py), a crafted blob name causes os.path.join to discard the intended base directory and write files to arbitrary locations on the host filesystem. This enables arbitrary file write when developers load skills from community-maintained or third-party GCS buckets.
Steps to Reproduce:
- Create a public GCS bucket (e.g.,
gs://test-bucket).
- Upload a test file with a traversal blob name, e.g.,
skills/my_skill/../../../../tmp/adk_traversal_test.txt.
- Run the following Python snippet to load the skill:
from google.adk.skills import load_skill_from_gcs_dir
load_skill_from_gcs_dir(bucket_name="test-bucket", skill_id="my_skill")
- Check your
/tmp/ directory. You will see /tmp/adk_traversal_test.txt has been created on the host system, successfully escaping the ADK's intended target directory.
Expected Behavior:
The ADK should sanitize and validate extracted GCS blob names. If a path contains traversal sequences (..) or is absolute, it should raise a ValueError before any file operations occur, ensuring files are only written within the intended local directory.
Observed Behavior:
The unsanitized relative path is passed directly to os.path.join(). If the path contains sufficient ../ sequences, os.path.join resolves it to a location outside the base directory, resulting in an arbitrary file write on the host system.
Environment Details:
- ADK Library Version:
latest (reproduces on current main branch)
- Desktop OS: All (Linux, macOS, Windows)
- Python Version: Python 3.x (Standard
os.path.join behavior)
Additional Context:
SECURITY NOTICE & EXPLOITABILITY: This issue tracks a vulnerability reported to the Google OSS VRP (Issue #499557362), which has been officially triaged by the Google Security Team.
To demonstrate the critical severity of this bug to the VRP team, I successfully verified that this pattern is actively exploitable in the wild. I identified unclaimed GCS buckets that were hardcoded in existing ADK community repositories (e.g., gs://rad-skills), registered one, and uploaded a benign payload with a traversal blob name.
When a developer clones the repo and loads the skill via the standard workflow, the arbitrary file write chains directly into runpy.run_path(), resulting in live, unauthenticated Remote Code Execution (RCE) on the host machine with zero user interaction beyond running the standard agent.
FIX SUBMITTED: I have already submitted a complete patch that resolves this issue in PR #5281. The PR adds os.path.normpath() validation to block malicious blob names safely. All formatting checks and conflicts have been resolved, and it is awaiting maintainer workflow approval and review.
DISCLOSURE: The planned coordinated disclosure date for this vulnerability is July 3, 2026. I would appreciate it if a maintainer could review and merge PR #5281 prior to this date to protect the ecosystem.
Minimal Reproduction Code:
See Steps to Reproduce above.
Required Information
Describe the Bug:
The
load_skill_from_gcs_dirfunction in_utils.pyextracts blob names from GCS and passes them toos.path.join()without sanitization. Because GCS allows blob names containing traversal sequences (e.g.,skills/my_skill/../../../../tmp/malicious.py), a crafted blob name causesos.path.jointo discard the intended base directory and write files to arbitrary locations on the host filesystem. This enables arbitrary file write when developers load skills from community-maintained or third-party GCS buckets.Steps to Reproduce:
gs://test-bucket).skills/my_skill/../../../../tmp/adk_traversal_test.txt./tmp/directory. You will see/tmp/adk_traversal_test.txthas been created on the host system, successfully escaping the ADK's intended target directory.Expected Behavior:
The ADK should sanitize and validate extracted GCS blob names. If a path contains traversal sequences (
..) or is absolute, it should raise aValueErrorbefore any file operations occur, ensuring files are only written within the intended local directory.Observed Behavior:
The unsanitized relative path is passed directly to
os.path.join(). If the path contains sufficient../sequences,os.path.joinresolves it to a location outside the base directory, resulting in an arbitrary file write on the host system.Environment Details:
latest(reproduces on currentmainbranch)os.path.joinbehavior)Additional Context:
SECURITY NOTICE & EXPLOITABILITY: This issue tracks a vulnerability reported to the Google OSS VRP (Issue #499557362), which has been officially triaged by the Google Security Team.
To demonstrate the critical severity of this bug to the VRP team, I successfully verified that this pattern is actively exploitable in the wild. I identified unclaimed GCS buckets that were hardcoded in existing ADK community repositories (e.g.,
gs://rad-skills), registered one, and uploaded a benign payload with a traversal blob name.When a developer clones the repo and loads the skill via the standard workflow, the arbitrary file write chains directly into
runpy.run_path(), resulting in live, unauthenticated Remote Code Execution (RCE) on the host machine with zero user interaction beyond running the standard agent.FIX SUBMITTED: I have already submitted a complete patch that resolves this issue in PR #5281. The PR adds
os.path.normpath()validation to block malicious blob names safely. All formatting checks and conflicts have been resolved, and it is awaiting maintainer workflow approval and review.DISCLOSURE: The planned coordinated disclosure date for this vulnerability is July 3, 2026. I would appreciate it if a maintainer could review and merge PR #5281 prior to this date to protect the ecosystem.
Minimal Reproduction Code:
See Steps to Reproduce above.