Skip to content

[BUG] Memory REST API permits cross-user conversation access by conversationId #1315

Description

@3em0

Describe the bug

The memory REST API handlers in @voltagent/server-core perform object lookup by caller-supplied conversationId and optional query/body values, but they do not receive or enforce the authenticated principal from the server auth middleware.

As a result, an authenticated caller who knows or guesses another user's conversationId can read that conversation, list its messages, read conversation-scoped working memory, and delete the conversation. This is an object-level authorization issue / IDOR affecting the memory API surface.

Relevant code paths:

  • packages/server-core/src/handlers/memory.handlers.ts
    • handleGetMemoryConversation() fetches resolved.memory.getConversation(conversationId) and returns it without owner/resource authorization.
    • handleListMemoryConversationMessages() fetches the conversation, then falls back to conversation.userId when query.userId is omitted, which returns the victim's messages.
    • handleGetMemoryWorkingMemory() fetches by conversationId and falls back to conversation.userId.
    • handleDeleteMemoryConversation() deletes by conversationId only.
  • packages/server-hono/src/routes/memory.routes.ts, packages/server-elysia/src/routes/memory.routes.ts, and packages/serverless-hono/src/routes.ts pass query/body data into these handlers, but do not pass the authenticated principal for object-level authorization checks.

Steps To Reproduce

  1. Use a VoltAgent app exposing the memory REST API with any memory adapter and authentication enabled.

  2. Create a conversation as victim-user, for example conv-victim-001, and store at least one message or conversation-scoped working memory entry.

  3. Authenticate as a different user, for example attacker-user.

  4. Request the victim conversation by ID:

    GET /api/memory/conversations/conv-victim-001
    Authorization: Bearer <attacker-token>
  5. Request the victim messages without providing userId:

    GET /api/memory/conversations/conv-victim-001/messages
    Authorization: Bearer <attacker-token>
  6. Request victim working memory:

    GET /api/memory/conversations/conv-victim-001/working-memory
    Authorization: Bearer <attacker-token>
  7. Optionally delete the victim conversation:

    DELETE /api/memory/conversations/conv-victim-001
    Authorization: Bearer <attacker-token>
  8. Run the included safe local synthetic PoC:

    node poc_memory_idor.mjs

    The PoC does not access real services or data. It models the relevant handler behavior and demonstrates cross-user read and delete using synthetic records.

Expected behavior

Memory API handlers should bind every conversation/message/working-memory operation to the authenticated principal and the expected resource/agent scope. A caller authenticated as attacker-user should not be able to read, update, clone, search, or delete a conversation owned by victim-user unless an explicit authorization policy grants that access.

For example:

  • GET by conversationId should verify conversation.userId === authenticatedUser.id or an equivalent policy decision before returning the object.
  • Message listing should not fall back to conversation.userId for a different authenticated caller.
  • Delete/update/clone operations should enforce the same owner/resource policy before mutating state.
  • Query/body userId must not be trusted as an authorization source.

Packages

  • @voltagent/server-core up to 2.1.17
  • @voltagent/server-hono up to 2.0.13
  • @voltagent/server-elysia up to 2.0.8
  • @voltagent/serverless-hono up to the version in the current repository
  • Memory adapters used behind the API, including @voltagent/core, @voltagent/libsql, @voltagent/postgres, @voltagent/supabase, and @voltagent/voltagent-memory

Additional Context

This is security-sensitive. The repository's SECURITY.md requests reporting suspected vulnerabilities via GitHub Security Advisories rather than public issues. This file is formatted according to .github/ISSUE_TEMPLATE/bug_report.yml as requested, but it should be submitted privately unless the maintainers approve public disclosure.

Tested against local commit 39978061763e621c9dea6fd7796488bd2089279b and rechecked against origin/main commit 5be7626632cc7fb8798ec0a06774af6560184e52; the relevant memory handler behavior is still present on origin/main.

Suggested remediation:

  • Pass authenticated user context from server middleware into memory route handlers for all methods, including GET/DELETE.
  • Enforce object-level authorization in server-core before returning or mutating conversations, messages, working memory, vector search results, or cloned conversations.
  • Treat userId, resourceId, and agentId query/body values as selectors only after they are validated against the authenticated principal and authorization policy.
  • Add regression tests for cross-user read, update, clone, delete, and search attempts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions