Skip to content

Avoid dotted ID collisions in VertexAiRagMemoryService memory lookups #5294

Closed

Description

@petrmarinec

Summary

VertexAiRagMemoryService stores Vertex RAG file display_name values as a dot-delimited string:

f"{session.app_name}.{session.user_id}.{session.id}"

search_memory() then accepts a retrieved context when its source_display_name starts with:

f"{app_name}.{user_id}."

This makes the client-side scope check ambiguous when IDs contain dots. For example, a memory stored for app_name="demo" and user_id="alice.smith" has a legacy display name beginning with demo.alice.smith.. A search for app_name="demo" and user_id="alice" also checks for the prefix demo.alice., so it can accept the other user's memory.

Impact

This can expose Vertex RAG-backed memory across users in the same app when one user ID is a dot-prefix of another user ID, such as alice and alice.smith. If an agent uses preload memory, the returned memory can be inserted into the next model request for the wrong user.

This appears to be a follow-up to the existing user scoping fix from #1019: the current code is intended to filter by app_name and user_id, but the dot-delimited representation is not unambiguous.

Expected behavior

Memory lookup should compare the stored app/user scope exactly. Dots in app_name, user_id, or session_id should stay inside their own component instead of changing how the display name is parsed.

Proposed fix

The prepared PR changes new Vertex RAG uploads to use an encoded v1 display-name format for app_name, user_id, and session_id. Search parsing then compares the decoded components exactly. For old data, it keeps compatibility only for the unambiguous legacy three-part app.user.session form and ignores ambiguous legacy names.

Validation

The prepared PR adds unit coverage that:

  • rejects a legacy collision such as demo.alice.smith.session_secret when searching as demo / alice
  • still accepts new encoded display names containing dotted app/user/session IDs
  • keeps unambiguous legacy demo.alice.legacy_session behavior

Local validation:

PYTHONPATH=src python -m pytest tests/unittests/memory -q
42 passed, 2 warnings

python -m isort --check-only src/google/adk/memory/vertex_ai_rag_memory_service.py tests/unittests/memory/test_vertex_ai_rag_memory_service.py
passed

python -m pyink --check --config pyproject.toml src/google/adk/memory/vertex_ai_rag_memory_service.py tests/unittests/memory/test_vertex_ai_rag_memory_service.py
passed

git diff --check -- src/google/adk/memory/vertex_ai_rag_memory_service.py tests/unittests/memory/test_vertex_ai_rag_memory_service.py
passed

Activity

  1. added
    services[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc
    on Apr 11, 2026
  2. added theissue type on Apr 11, 2026
  3. surajksharma07 commented on Apr 16, 2026

    @surajksharma07
    Collaborator

    @petrmarinec the startswith(f"{app_name}.{user_id}.") check in search_memory can't distinguish a field separator from a dot inside a user ID, which is exactly how alice silently picks up alice.smith's entries from the same corpus.

    The encoded v1 display-name approach in PR #5295 is the right call.
    The one area worth careful testing is the backward-compat path — specifically that unambiguous legacy entries (exactly 3 dot-segments, no in-field dots) still surface correctly, and that ambiguous ones are silently skipped rather than leaked.

    Could you do a quick smoke-test against a real corpus with mixed old-format and new-format entries before the review pass, just to confirm the legacy-compat logic holds up end-to-end?

  4. petrmarinec commented on Apr 16, 2026

    @petrmarinec
    ContributorAuthor

    Hi, I confirmed this with a real Vertex RAG corpus before the review pass.

    I ran a mixed old-format/new-format smoke test against a disposable Vertex RAG corpus.

    The corpus contained:

    • a new encoded v1 entry for app_name=demo, user_id=alice
    • an unambiguous legacy entry with display name demo.alice.legacy-...
    • an ambiguous legacy entry with display name demo.alice.smith.secret-...

    Raw RAG retrieval returned all three uploaded entries.

    Then I queried through the actual VertexAiRagMemoryService.search_memory(app_name="demo", user_id="alice", ...) path.

    The filtered result included the new encoded v1 Alice entry and the unambiguous legacy demo.alice.legacy-... entry. It did not include the ambiguous legacy demo.alice.smith.secret-... entry.

  5. surajksharma07 commented on Apr 19, 2026

    @surajksharma07
    Collaborator

    @petrmarinec that's exactly the validation we needed — raw retrieval surfacing all three entries is the important detail here, because it confirms the attack surface is real (the corpus hands back alice.smith's entry without any server-side scoping) and the client-side filter in _parse_display_name is the only gate.

    The fact that the ambiguous legacy name was silently dropped rather than passed through proves the compat logic is correct under real-corpus conditions, not just in unit tests — that's the result we were looking for.

    PR #5295 looks good — the three-case split (v1 accept, unambiguous-legacy accept, ambiguous-legacy drop) is holding up end-to-end.

    Team is looking more into it.

  6. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    and removed
    request clarification[Status] The maintainer need clarification or more information from the author
    on Apr 19, 2026
  7. surajksharma07 commented on Apr 19, 2026

    @surajksharma07
    Collaborator

    @DeanChensj Please have a look into it once.

  8. added a commit that references this issue on Aug 11, 2026
    898c4d2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

needs review[Status] The PR/issue is awaiting review from the maintainerservices[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