Skip to content

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

@3em0

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions