Skip to content

FileArtifactService user_id with '/' composes onto another user's session artifacts#7067

Description

@artemkulyk

馃敶 Required Information

Describe the Bug:
FileArtifactService stores artifacts under root/apps/{app_name}/users/{user_id}/[sessions/{session_id}/]artifacts/{filename}. validate_path_segment rejects traversal (..), absolute paths, drive letters, and null bytes, but permits / and \ in user_id.

A caller whose user_id is u1/sessions/s2 therefore has its user-scoped storage composed onto exactly victim user u1's session s2 tree. Read, overwrite, and delete of the victim's payload succeed with no .. segments.

This is a service-level issue. Stock HTTP artifact endpoints are not reachable this way (Starlette does not decode %2F inside a path segment). GcsArtifactService is not this collision (blob layout has no literal sessions/artifacts segments). The shared validator should still reject separators so identifiers remain a single path segment.

Google VRP issue 557708759 was closed as Infeasible (not tracked as a security bug) with a request to file this publicly.

Steps to Reproduce:

  1. save_artifact(app_name, user_id="u1", session_id="s2", filename="notes", ...) (session-scoped).
  2. Call load_artifact / save_artifact / delete_artifact with user_id="u1/sessions/s2" and the same filename (user-scoped).
  3. Observe the victim's session artifact is read, overwritten, or deleted.

Expected Behavior:
user_id, app_name, and session_id must not contain path separators. validate_path_segment raises InputValidationError. Nested filenames remain allowed.

Observed Behavior:
validate_path_segment("u1/sessions/s2", "user_id") succeeds. _base_root joins the slash into the tree, colliding with users/u1/sessions/s2/artifacts.

Environment Details:

  • ADK Library Version (pip show google-adk): 2.8.0 (a119dd7751082dbbd9a65f71e359abdc2be659cc and current main)
  • Desktop OS: macOS
  • Python Version (python -V): 3.12 / 3.13

Model Information:

  • Are you using LiteLLM: N/A (library-level FileArtifactService)
  • Which model is being used: N/A

馃煛 Optional Information

Regression:
Present as long as validate_path_segment allows / in identifiers used by FileArtifactService._base_root.

Minimal Reproduction Code:

# victim
await svc.save_artifact(app_name="myapp", user_id="u1", session_id="s2",
                        filename="notes", artifact={"text": "VICTIM-SECRET"})
# attacker
await svc.load_artifact(app_name="myapp", user_id="u1/sessions/s2", filename="notes")

Additional Context:
Exploitable only where embedding apps pass slash-containing user_id values (hierarchical IDs). Suggested fix: reject / and \ in validate_path_segment, matching evaluation/_path_validation.py.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

services[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions