Skip to content

Security: Path Traversal in _load_skill_from_gcs_dir enables arbitrary file write (VRP #499557362) #5603

@BISHT-CX

Description

@BISHT-CX

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:

  1. Create a public GCS bucket (e.g., gs://test-bucket).
  2. Upload a test file with a traversal blob name, e.g., skills/my_skill/../../../../tmp/adk_traversal_test.txt.
  3. 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")
  4. 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.

Metadata

Metadata

Assignees

Labels

core[Component] This issue is related to the core interface and implementation

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions