#1371·voltagent

Memory API Missing Ownership Check -- Cross-User Conversation Access (IDOR) in @voltagent/server-hono

Author: geo-chenCreated Jul 3, 2026Updated Jul 3, 2026
Labelsbug

Describe the bug

reported on 2 June 2026 via email but no response:

I am reporting a missing authorization check in the VoltAgent memory REST API that allows any authenticated user to read, modify, and delete another user's conversation history. On the default deployment (no auth configured), the same operations are available to unauthenticated callers.

Summary of the issue:

The handlers in packages/server-core/src/handlers/memory.handlers.ts (handleGetMemoryConversation, handleListMemoryConversationMessages, handleUpdateMemoryConversation, handleDeleteMemoryConversation) fetch and operate on conversations by ID without verifying that the requesting user is the conversation owner. The authenticated user's identity is injected into the request context by the auth middleware but is never read by these handlers.

Steps To Reproduce

(confirmed against voltagent commit 74fe5e9, latest HEAD):

With JWT auth enabled and two users (Alice and Bob each holding a valid token for themselves):

  1. Alice creates a conversation and saves a message:

POST /api/memory/conversations {"userId":"user-alice","title":"Alice Private"} --> {"id":"uk7OOubHrbF9pKsL","userId":"user-alice",...}

POST /api/memory/save-messages {"userId":"user-alice","conversationId":"uk7OOubHrbF9pKsL","messages":[{"role":"user","content":"Confidential: Bank account 1234-5678-9012",...}]} --> {"saved":1}

  1. Bob (authenticated with his own valid JWT, user-bob) reads Alice's conversation:

GET /api/memory/conversations/uk7OOubHrbF9pKsL/messages Authorization: Bearer <bob's token> --> {"conversation":{"userId":"user-alice",...},"messages":[{"parts":[{"text":"Confidential: Bank account 1234-5678-9012"}]}]}

  1. Bob modifies Alice's conversation metadata:

PATCH /api/memory/conversations/uk7OOubHrbF9pKsL Authorization: Bearer <bob's token> {"title":"TAMPERED BY BOB"} --> {"conversation":{"userId":"user-alice","title":"TAMPERED BY BOB",...}}

  1. Bob deletes Alice's conversation:

DELETE /api/memory/conversations/uk7OOubHrbF9pKsL Authorization: Bearer <bob's token> --> {"deleted":true}

Additionally, GET /api/memory/conversations?userId=user-alice (passing the victim's userId as a query param) returns all of Alice's conversations to any authenticated caller, without checking whether the caller is Alice.

Suggested fix: In each memory handler, extract the authenticated user's identity from the request context and verify it matches the conversation's stored userId before returning or modifying data. The list endpoint should ignore the client-supplied userId parameter and use only the identity from the verified token.

This was tested against the current HEAD commit 74fe5e9 using a locally built server with the published npm packages @voltagent/server-hono and @voltagent/server-core.

Expected behavior

Packages

Additional Context

No response