diff --git a/.changeset/tender-memory-ownership.md b/.changeset/tender-memory-ownership.md
new file mode 100644
index 000000000..7ac239f05
--- /dev/null
+++ b/.changeset/tender-memory-ownership.md
@@ -0,0 +1,13 @@
+---
+"@voltagent/core": patch
+"@voltagent/cloudflare-d1": patch
+"@voltagent/libsql": patch
+"@voltagent/postgres": patch
+"@voltagent/server-core": patch
+"@voltagent/server-elysia": patch
+"@voltagent/server-hono": patch
+"@voltagent/supabase": patch
+"@voltagent/voltagent-memory": patch
+---
+
+Harden guarded memory conversation mutations by preserving ownership checks across vector cleanup, D1 deletes, and managed-memory remote mutations. Raise adapter peer dependency minimums to require the core release that exports ownership mismatch errors.
diff --git a/packages/cloudflare-d1/package.json b/packages/cloudflare-d1/package.json
index c2b2ccb7f..b55956e00 100644
--- a/packages/cloudflare-d1/package.json
+++ b/packages/cloudflare-d1/package.json
@@ -31,7 +31,7 @@
   "main": "dist/index.js",
   "module": "dist/index.mjs",
   "peerDependencies": {
-    "@voltagent/core": "^2.0.0",
+    "@voltagent/core": "^2.9.1",
     "@voltagent/logger": "^2.0.0",
     "ai": "^6.0.0"
   },
diff --git a/packages/cloudflare-d1/src/memory-adapter.spec.ts b/packages/cloudflare-d1/src/memory-adapter.spec.ts
index 36ad60ac6..0c12b0a8b 100644
--- a/packages/cloudflare-d1/src/memory-adapter.spec.ts
+++ b/packages/cloudflare-d1/src/memory-adapter.spec.ts
@@ -1,4 +1,5 @@
 import type { D1Database } from "@cloudflare/workers-types";
+import { ConversationOwnershipMismatchError } from "@voltagent/core";
 import { describe, expect, it, vi } from "vitest";
 import { D1MemoryAdapter } from "./memory-adapter";
 
@@ -81,3 +82,79 @@ describe("D1MemoryAdapter queryWorkflowRuns", () => {
     ]);
   });
 });
+
+describe("D1MemoryAdapter conversation ownership guards", () => {
+  const row = {
+    id: "conv-1",
+    resource_id: "agent-1",
+    user_id: "user-1",
+    title: "Original",
+    metadata: "{}",
+    created_at: "2024-01-01T00:00:00.000Z",
+    updated_at: "2024-01-01T00:00:00.000Z",
+  };
+
+  it("adds expectedUserId to updateConversation mutations", async () => {
+    vi.spyOn(D1MemoryAdapter.prototype as any, "ensureInitialized").mockResolvedValue(undefined);
+    const adapter = new D1MemoryAdapter({ binding: createMockBinding(), tablePrefix: "test" });
+    vi.spyOn(adapter as any, "all")
+      .mockResolvedValueOnce([row])
+      .mockResolvedValueOnce([{ ...row, title: "Updated" }]);
+    const runSpy = vi.spyOn(adapter as any, "run").mockResolvedValue({ meta: { changes: 1 } });
+
+    await (adapter as any).updateConversation(
+      "conv-1",
+      { title: "Updated" },
+      { expectedUserId: "user-1" },
+    );
+
+    const [sql, args] = runSpy.mock.calls[0];
+    expect(sql).toContain("WHERE id = ? AND user_id = ?");
+    expect(args).toEqual([expect.any(String), "Updated", "conv-1", "user-1"]);
+  });
+
+  it("rejects guarded updates before mutating when the existing owner does not match", async () => {
+    vi.spyOn(D1MemoryAdapter.prototype as any, "ensureInitialized").mockResolvedValue(undefined);
+    const adapter = new D1MemoryAdapter({ binding: createMockBinding(), tablePrefix: "test" });
+    vi.spyOn(adapter as any, "all").mockResolvedValueOnce([{ ...row, user_id: "user-2" }]);
+    const runSpy = vi.spyOn(adapter as any, "run").mockResolvedValue({ meta: { changes: 1 } });
+
+    await expect(
+      (adapter as any).updateConversation(
+        "conv-1",
+        { title: "Updated" },
+        { expectedUserId: "user-1" },
+      ),
+    ).rejects.toBeInstanceOf(ConversationOwnershipMismatchError);
+
+    expect(runSpy).not.toHaveBeenCalled();
+  });
+
+  it("uses the guarded parent delete and relies on cascades for owned child rows", async () => {
+    vi.spyOn(D1MemoryAdapter.prototype as any, "ensureInitialized").mockResolvedValue(undefined);
+    const adapter = new D1MemoryAdapter({ binding: createMockBinding(), tablePrefix: "test" });
+    const runSpy = vi.spyOn(adapter as any, "run").mockResolvedValue({ meta: { changes: 1 } });
+
+    await (adapter as any).deleteConversation("conv-1", { expectedUserId: "user-1" });
+
+    expect(runSpy).toHaveBeenCalledTimes(1);
+    const [sql, args] = runSpy.mock.calls[0];
+    expect(sql).toContain("DELETE FROM test_conversations WHERE id = ? AND user_id = ?");
+    expect(args).toEqual(["conv-1", "user-1"]);
+  });
+
+  it("rejects guarded deletes without deleting child rows when no owned row is affected", async () => {
+    vi.spyOn(D1MemoryAdapter.prototype as any, "ensureInitialized").mockResolvedValue(undefined);
+    const adapter = new D1MemoryAdapter({ binding: createMockBinding(), tablePrefix: "test" });
+    const runSpy = vi.spyOn(adapter as any, "run").mockResolvedValue({ meta: { changes: 0 } });
+
+    await expect(
+      (adapter as any).deleteConversation("conv-1", { expectedUserId: "user-1" }),
+    ).rejects.toBeInstanceOf(ConversationOwnershipMismatchError);
+
+    expect(runSpy).toHaveBeenCalledTimes(1);
+    const [sql, args] = runSpy.mock.calls[0];
+    expect(sql).toContain("DELETE FROM test_conversations WHERE id = ? AND user_id = ?");
+    expect(args).toEqual(["conv-1", "user-1"]);
+  });
+});
diff --git a/packages/cloudflare-d1/src/memory-adapter.ts b/packages/cloudflare-d1/src/memory-adapter.ts
index dd0fe9204..0ad4f79e1 100644
--- a/packages/cloudflare-d1/src/memory-adapter.ts
+++ b/packages/cloudflare-d1/src/memory-adapter.ts
@@ -8,9 +8,11 @@ import {
   AgentRegistry,
   ConversationAlreadyExistsError,
   ConversationNotFoundError,
+  ConversationOwnershipMismatchError,
 } from "@voltagent/core";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -102,8 +104,8 @@ export class D1MemoryAdapter implements StorageAdapter {
     return args.length > 0 ? statement.bind(...args) : statement;
   }
 
-  private async run(sql: string, args: unknown[] = []): Promise<void> {
-    await this.buildStatement(sql, args).run();
+  private async run(sql: string, args: unknown[] = []): Promise<{ meta?: { changes?: number } }> {
+    return (await this.buildStatement(sql, args).run()) as { meta?: { changes?: number } };
   }
 
   private async all<T extends D1Row = D1Row>(sql: string, args: unknown[] = []): Promise<T[]> {
@@ -1037,6 +1039,7 @@ export class D1MemoryAdapter implements StorageAdapter {
   async updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation> {
     await this.ensureInitialized();
 
@@ -1046,6 +1049,10 @@ export class D1MemoryAdapter implements StorageAdapter {
       throw new ConversationNotFoundError(id);
     }
 
+    if (options?.expectedUserId !== undefined && conversation.userId !== options.expectedUserId) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
     const now = new Date().toISOString();
     const fieldsToUpdate: string[] = ["updated_at = ?"];
     const args: unknown[] = [now];
@@ -1066,12 +1073,21 @@ export class D1MemoryAdapter implements StorageAdapter {
     }
 
     args.push(id);
+    let whereClause = "WHERE id = ?";
+    if (options?.expectedUserId !== undefined) {
+      whereClause += " AND user_id = ?";
+      args.push(options.expectedUserId);
+    }
 
-    await this.run(
-      `UPDATE ${conversationsTable} SET ${fieldsToUpdate.join(", ")} WHERE id = ?`,
+    const result = await this.run(
+      `UPDATE ${conversationsTable} SET ${fieldsToUpdate.join(", ")} ${whereClause}`,
       args,
     );
 
+    if (options?.expectedUserId !== undefined && result.meta?.changes === 0) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
     const updated = await this.getConversation(id);
     if (!updated) {
       throw new Error(`Conversation not found after update: ${id}`);
@@ -1079,13 +1095,24 @@ export class D1MemoryAdapter implements StorageAdapter {
     return updated;
   }
 
-  async deleteConversation(id: string): Promise<void> {
+  async deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void> {
     await this.ensureInitialized();
 
     const conversationsTable = `${this.tablePrefix}_conversations`;
     const messagesTable = `${this.tablePrefix}_messages`;
     const stepsTable = `${this.tablePrefix}_steps`;
 
+    if (options?.expectedUserId !== undefined) {
+      const result = await this.run(
+        `DELETE FROM ${conversationsTable} WHERE id = ? AND user_id = ?`,
+        [id, options.expectedUserId],
+      );
+      if (result.meta?.changes === 0) {
+        throw new ConversationOwnershipMismatchError(id);
+      }
+      return;
+    }
+
     await this.run(`DELETE FROM ${messagesTable} WHERE conversation_id = ?`, [id]);
     await this.run(`DELETE FROM ${stepsTable} WHERE conversation_id = ?`, [id]);
     await this.run(`DELETE FROM ${conversationsTable} WHERE id = ?`, [id]);
diff --git a/packages/core/src/memory/adapters/storage/in-memory.ts b/packages/core/src/memory/adapters/storage/in-memory.ts
index 76dccd800..d19533d1d 100644
--- a/packages/core/src/memory/adapters/storage/in-memory.ts
+++ b/packages/core/src/memory/adapters/storage/in-memory.ts
@@ -6,9 +6,14 @@
 import { deepClone } from "@voltagent/internal/utils";
 import type { UIMessage } from "ai";
 import type { OperationContext } from "../../../agent/types";
-import { ConversationAlreadyExistsError, ConversationNotFoundError } from "../../errors";
+import {
+  ConversationAlreadyExistsError,
+  ConversationNotFoundError,
+  ConversationOwnershipMismatchError,
+} from "../../errors";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -424,12 +429,17 @@ export class InMemoryStorageAdapter implements StorageAdapter {
   async updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation> {
     const conversation = this.conversations.get(id);
     if (!conversation) {
       throw new ConversationNotFoundError(id);
     }
 
+    if (options?.expectedUserId !== undefined && conversation.userId !== options.expectedUserId) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
     const updatedConversation: Conversation = {
       ...conversation,
       ...updates,
@@ -443,12 +453,16 @@ export class InMemoryStorageAdapter implements StorageAdapter {
   /**
    * Delete a conversation
    */
-  async deleteConversation(id: string): Promise<void> {
+  async deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void> {
     const conversation = this.conversations.get(id);
     if (!conversation) {
       throw new ConversationNotFoundError(id);
     }
 
+    if (options?.expectedUserId !== undefined && conversation.userId !== options.expectedUserId) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
     // Delete conversation
     this.conversations.delete(id);
 
diff --git a/packages/core/src/memory/errors.ts b/packages/core/src/memory/errors.ts
index 853fa4b01..1795aa3d7 100644
--- a/packages/core/src/memory/errors.ts
+++ b/packages/core/src/memory/errors.ts
@@ -63,6 +63,19 @@ export class ConversationNotFoundError extends MemoryV2Error {
   }
 }
 
+/**
+ * Error thrown when a guarded conversation mutation no longer matches the expected owner
+ */
+export class ConversationOwnershipMismatchError extends MemoryV2Error {
+  constructor(conversationId: string) {
+    super(`Conversation ownership mismatch: ${conversationId}`, "CONVERSATION_OWNERSHIP_MISMATCH", {
+      conversationId,
+    });
+    this.name = "ConversationOwnershipMismatchError";
+    Object.setPrototypeOf(this, ConversationOwnershipMismatchError.prototype);
+  }
+}
+
 /**
  * Error thrown when trying to create a conversation that already exists
  */
diff --git a/packages/core/src/memory/index.spec.ts b/packages/core/src/memory/index.spec.ts
new file mode 100644
index 000000000..89308a056
--- /dev/null
+++ b/packages/core/src/memory/index.spec.ts
@@ -0,0 +1,84 @@
+import type { UIMessage } from "ai";
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import { InMemoryStorageAdapter } from "./adapters/storage/in-memory";
+import { InMemoryVectorAdapter } from "./adapters/vector/in-memory";
+import { Memory } from "./index";
+
+describe("Memory conversation mutation guards", () => {
+  let storage: InMemoryStorageAdapter;
+  let vector: InMemoryVectorAdapter;
+  let memory: Memory;
+
+  beforeEach(async () => {
+    storage = new InMemoryStorageAdapter();
+    vector = new InMemoryVectorAdapter();
+    memory = new Memory({
+      storage,
+      vector,
+    });
+
+    await memory.createConversation({
+      id: "conv-1",
+      userId: "user-1",
+      resourceId: "agent-1",
+      title: "Conversation",
+      metadata: {},
+    });
+  });
+
+  afterEach(() => {
+    vi.restoreAllMocks();
+  });
+
+  it("continues unguarded deletes when vector cleanup cannot read the conversation", async () => {
+    const readError = new Error("read unavailable");
+    const getSpy = vi.spyOn(storage, "getConversation").mockRejectedValueOnce(readError);
+    const deleteSpy = vi.spyOn(storage, "deleteConversation");
+    const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
+
+    await expect(memory.deleteConversation("conv-1")).resolves.toBeUndefined();
+
+    expect(getSpy).toHaveBeenCalledWith("conv-1");
+    expect(deleteSpy).toHaveBeenCalledWith("conv-1", undefined);
+    expect(warnSpy).toHaveBeenCalledWith(
+      "Failed to delete vectors for conversation conv-1:",
+      readError,
+    );
+    await expect(storage.getConversation("conv-1")).resolves.toBeNull();
+  });
+
+  it("does not re-read vectors for guarded deletes when ownership lookup finds no conversation", async () => {
+    const replacementConversation = {
+      id: "conv-1",
+      userId: "user-2",
+      resourceId: "agent-1",
+      title: "Replacement",
+      metadata: {},
+      createdAt: "2024-01-01T00:00:00.000Z",
+      updatedAt: "2024-01-01T00:00:00.000Z",
+    };
+    const deleteError = new Error("missing conversation");
+    const getSpy = vi
+      .spyOn(storage, "getConversation")
+      .mockResolvedValueOnce(null)
+      .mockResolvedValueOnce(replacementConversation);
+    const secretMessage: UIMessage<{ createdAt: Date }> = {
+      id: "msg-1",
+      role: "user",
+      parts: [{ type: "text", text: "secret" }],
+      metadata: { createdAt: new Date() },
+    };
+    const getMessagesSpy = vi.spyOn(storage, "getMessages").mockResolvedValueOnce([secretMessage]);
+    const deleteBatchSpy = vi.spyOn(vector, "deleteBatch");
+    const deleteSpy = vi.spyOn(storage, "deleteConversation").mockRejectedValueOnce(deleteError);
+
+    await expect(memory.deleteConversation("conv-1", { expectedUserId: "user-1" })).rejects.toThrow(
+      deleteError,
+    );
+
+    expect(getSpy).toHaveBeenCalledTimes(1);
+    expect(deleteSpy).toHaveBeenCalledWith("conv-1", { expectedUserId: "user-1" });
+    expect(getMessagesSpy).not.toHaveBeenCalled();
+    expect(deleteBatchSpy).not.toHaveBeenCalled();
+  });
+});
diff --git a/packages/core/src/memory/index.ts b/packages/core/src/memory/index.ts
index a63206f2f..1e0ee7453 100644
--- a/packages/core/src/memory/index.ts
+++ b/packages/core/src/memory/index.ts
@@ -7,9 +7,14 @@ import type { UIMessage } from "ai";
 import type { z } from "zod";
 import type { OperationContext } from "../agent/types";
 import { AiSdkEmbeddingAdapter } from "./adapters/embedding/ai-sdk";
-import { EmbeddingAdapterNotConfiguredError, VectorAdapterNotConfiguredError } from "./errors";
+import {
+  ConversationOwnershipMismatchError,
+  EmbeddingAdapterNotConfiguredError,
+  VectorAdapterNotConfiguredError,
+} from "./errors";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -280,19 +285,34 @@ export class Memory {
   async updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation> {
-    return this.storage.updateConversation(id, updates);
+    return this.storage.updateConversation(id, updates, options);
   }
 
   /**
    * Delete a conversation
    */
-  async deleteConversation(id: string): Promise<void> {
-    // If vector adapter is configured, delete associated vectors
-    if (this.vector) {
+  async deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void> {
+    let conversation: Conversation | null = null;
+
+    if (options?.expectedUserId !== undefined) {
+      conversation = await this.storage.getConversation(id);
+
+      if (conversation && conversation.userId !== options.expectedUserId) {
+        throw new ConversationOwnershipMismatchError(id);
+      }
+    }
+
+    // If vector adapter is configured, delete associated vectors.
+    // For guarded deletes, do not re-fetch when the ownership lookup found no
+    // conversation: a same-ID conversation may have been recreated for another
+    // owner before the guarded storage mutation runs.
+    const canCleanVectors = options?.expectedUserId === undefined || conversation !== null;
+    if (this.vector && canCleanVectors) {
       try {
-        // Try to get the conversation first to get userId
-        const conversation = await this.storage.getConversation(id);
+        conversation ??= await this.storage.getConversation(id);
+
         if (conversation) {
           // Get all messages to find vector IDs
           const messages = await this.storage.getMessages(conversation.userId, id);
@@ -307,7 +327,7 @@ export class Memory {
       }
     }
 
-    return this.storage.deleteConversation(id);
+    return this.storage.deleteConversation(id, options);
   }
 
   // ============================================================================
diff --git a/packages/core/src/memory/types.ts b/packages/core/src/memory/types.ts
index 3f595cd07..ba47528fa 100644
--- a/packages/core/src/memory/types.ts
+++ b/packages/core/src/memory/types.ts
@@ -58,6 +58,10 @@ export type ConversationQueryOptions = {
   orderDirection?: "ASC" | "DESC";
 };
 
+export type ConversationMutationOptions = {
+  expectedUserId?: string;
+};
+
 /**
  * Options for getting messages
  */
@@ -443,8 +447,9 @@ export interface StorageAdapter {
   updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation>;
-  deleteConversation(id: string): Promise<void>;
+  deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void>;
 
   saveConversationSteps?(steps: ConversationStepRecord[]): Promise<void>;
   getConversationSteps?(
diff --git a/packages/core/src/voltops/client.ts b/packages/core/src/voltops/client.ts
index 995885088..64c01864f 100644
--- a/packages/core/src/voltops/client.ts
+++ b/packages/core/src/voltops/client.ts
@@ -13,6 +13,7 @@ import { ResourceType, buildLogContext, buildVoltOpsLogMessage } from "../logger
 import type { SearchResult, VectorItem } from "../memory/adapters/vector/types";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -467,8 +468,8 @@ export class VoltOpsClient implements IVoltOpsClient {
           this.getManagedMemoryConversation(databaseId, conversationId),
         query: (databaseId, options) => this.queryManagedMemoryConversations(databaseId, options),
         update: (databaseId, input) => this.updateManagedMemoryConversation(databaseId, input),
-        delete: (databaseId, conversationId) =>
-          this.deleteManagedMemoryConversation(databaseId, conversationId),
+        delete: (databaseId, conversationId, options) =>
+          this.deleteManagedMemoryConversation(databaseId, conversationId, options),
       },
       workingMemory: {
         get: (databaseId, input) => this.getManagedMemoryWorkingMemory(databaseId, input),
@@ -817,13 +818,18 @@ export class VoltOpsClient implements IVoltOpsClient {
     databaseId: string,
     input: ManagedMemoryUpdateConversationInput,
   ): Promise<Conversation> {
+    const body = {
+      updates: input.updates,
+      ...(input.expectedUserId !== undefined ? { expectedUserId: input.expectedUserId } : {}),
+    };
+
     const payload = await this.request<{
       success: boolean;
       data?: { conversation?: Conversation };
     }>(
       "PATCH",
       `/managed-memory/projects/databases/${databaseId}/conversations/${input.conversationId}`,
-      { updates: input.updates },
+      body,
     );
 
     if (!payload?.success || !payload.data?.conversation) {
@@ -836,10 +842,16 @@ export class VoltOpsClient implements IVoltOpsClient {
   private async deleteManagedMemoryConversation(
     databaseId: string,
     conversationId: string,
+    options?: ConversationMutationOptions,
   ): Promise<void> {
+    const body =
+      options?.expectedUserId !== undefined
+        ? { expectedUserId: options.expectedUserId }
+        : undefined;
     const payload = await this.request<{ success: boolean }>(
       "DELETE",
       `/managed-memory/projects/databases/${databaseId}/conversations/${conversationId}`,
+      body,
     );
 
     if (!payload?.success) {
diff --git a/packages/core/src/voltops/types.ts b/packages/core/src/voltops/types.ts
index 8eb0608ee..03788e28b 100644
--- a/packages/core/src/voltops/types.ts
+++ b/packages/core/src/voltops/types.ts
@@ -12,6 +12,7 @@ import type { BaseMessage } from "../agent/providers/base/types";
 import type { SearchResult, VectorItem } from "../memory/adapters/vector/types";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -1239,6 +1240,7 @@ export interface ManagedMemoryDeleteVectorsInput {
 export interface ManagedMemoryUpdateConversationInput {
   conversationId: string;
   updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>;
+  expectedUserId?: string;
 }
 
 export interface ManagedMemoryWorkingMemoryInput {
@@ -1280,7 +1282,11 @@ export interface ManagedMemoryConversationsClient {
   get(databaseId: string, conversationId: string): Promise<Conversation | null>;
   query(databaseId: string, options: ConversationQueryOptions): Promise<Conversation[]>;
   update(databaseId: string, input: ManagedMemoryUpdateConversationInput): Promise<Conversation>;
-  delete(databaseId: string, conversationId: string): Promise<void>;
+  delete(
+    databaseId: string,
+    conversationId: string,
+    options?: ConversationMutationOptions,
+  ): Promise<void>;
 }
 
 export interface ManagedMemoryWorkingMemoryClient {
diff --git a/packages/libsql/package.json b/packages/libsql/package.json
index 0e2e1bf37..3c79fc44f 100644
--- a/packages/libsql/package.json
+++ b/packages/libsql/package.json
@@ -41,7 +41,7 @@
   "main": "dist/index.js",
   "module": "dist/index.mjs",
   "peerDependencies": {
-    "@voltagent/core": "^2.0.0",
+    "@voltagent/core": "^2.9.1",
     "@voltagent/logger": "^2.0.0",
     "ai": "^6.0.0"
   },
diff --git a/packages/libsql/src/memory-core.ts b/packages/libsql/src/memory-core.ts
index c2695a03b..99cf176ee 100644
--- a/packages/libsql/src/memory-core.ts
+++ b/packages/libsql/src/memory-core.ts
@@ -5,9 +5,14 @@
  */
 
 import type { Client } from "@libsql/client";
-import { ConversationAlreadyExistsError, ConversationNotFoundError } from "@voltagent/core";
+import {
+  ConversationAlreadyExistsError,
+  ConversationNotFoundError,
+  ConversationOwnershipMismatchError,
+} from "@voltagent/core";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -960,6 +965,7 @@ export class LibSQLMemoryCore implements StorageAdapter {
   async updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation> {
     await this.initialize();
 
@@ -969,6 +975,10 @@ export class LibSQLMemoryCore implements StorageAdapter {
       throw new ConversationNotFoundError(id);
     }
 
+    if (options?.expectedUserId !== undefined && conversation.userId !== options.expectedUserId) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
     const now = new Date().toISOString();
     const fieldsToUpdate: string[] = ["updated_at = ?"];
     const args: any[] = [now];
@@ -989,12 +999,21 @@ export class LibSQLMemoryCore implements StorageAdapter {
     }
 
     args.push(id);
+    let whereClause = "WHERE id = ?";
+    if (options?.expectedUserId !== undefined) {
+      whereClause += " AND user_id = ?";
+      args.push(options.expectedUserId);
+    }
 
-    await this.client.execute({
-      sql: `UPDATE ${conversationsTable} SET ${fieldsToUpdate.join(", ")} WHERE id = ?`,
+    const result = await this.client.execute({
+      sql: `UPDATE ${conversationsTable} SET ${fieldsToUpdate.join(", ")} ${whereClause}`,
       args,
     });
 
+    if (options?.expectedUserId !== undefined && result.rowsAffected === 0) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
     const updated = await this.getConversation(id);
     if (!updated) {
       throw new Error(`Conversation not found after update: ${id}`);
@@ -1002,15 +1021,26 @@ export class LibSQLMemoryCore implements StorageAdapter {
     return updated;
   }
 
-  async deleteConversation(id: string): Promise<void> {
+  async deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void> {
     await this.initialize();
 
     const conversationsTable = `${this.tablePrefix}_conversations`;
 
-    await this.client.execute({
-      sql: `DELETE FROM ${conversationsTable} WHERE id = ?`,
-      args: [id],
+    const args: any[] = [id];
+    let whereClause = "WHERE id = ?";
+    if (options?.expectedUserId !== undefined) {
+      whereClause += " AND user_id = ?";
+      args.push(options.expectedUserId);
+    }
+
+    const result = await this.client.execute({
+      sql: `DELETE FROM ${conversationsTable} ${whereClause}`,
+      args,
     });
+
+    if (options?.expectedUserId !== undefined && result.rowsAffected === 0) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
   }
 
   // ============================================================================
diff --git a/packages/libsql/src/memory-v2-adapter.spec.ts b/packages/libsql/src/memory-v2-adapter.spec.ts
index 2e2a429b9..c63bcdd01 100644
--- a/packages/libsql/src/memory-v2-adapter.spec.ts
+++ b/packages/libsql/src/memory-v2-adapter.spec.ts
@@ -3,6 +3,7 @@
  * Tests query shapes with mocked client
  */
 
+import { ConversationOwnershipMismatchError } from "@voltagent/core";
 import type { UIMessage } from "ai";
 import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
 import { LibSQLMemoryAdapter } from "./memory-v2-adapter";
@@ -135,4 +136,83 @@ describe.sequential("LibSQLMemoryAdapter - Advanced Behavior", () => {
       5,
     ]);
   });
+
+  it("adds expectedUserId to updateConversation mutations", async () => {
+    const existing = {
+      id: "conv-1",
+      resource_id: "agent-1",
+      user_id: "user-1",
+      title: "Original",
+      metadata: "{}",
+      created_at: "2024-01-01T00:00:00.000Z",
+      updated_at: "2024-01-01T00:00:00.000Z",
+    };
+
+    mockExecute
+      .mockResolvedValueOnce({ rows: [existing] })
+      .mockResolvedValueOnce({ rows: [], rowsAffected: 1 })
+      .mockResolvedValueOnce({ rows: [{ ...existing, title: "Updated" }] });
+
+    await (adapter as any).updateConversation(
+      "conv-1",
+      { title: "Updated" },
+      { expectedUserId: "user-1" },
+    );
+
+    const updateCall = mockExecute.mock.calls.find(([input]) =>
+      String(input.sql).includes("UPDATE test_conversations"),
+    )?.[0];
+    expect(updateCall.sql).toContain("WHERE id = ? AND user_id = ?");
+    expect(updateCall.args).toEqual([expect.any(String), "Updated", "conv-1", "user-1"]);
+  });
+
+  it("rejects guarded updates when the existing owner does not match", async () => {
+    const existing = {
+      id: "conv-1",
+      resource_id: "agent-1",
+      user_id: "user-2",
+      title: "Original",
+      metadata: "{}",
+      created_at: "2024-01-01T00:00:00.000Z",
+      updated_at: "2024-01-01T00:00:00.000Z",
+    };
+
+    mockExecute.mockResolvedValueOnce({ rows: [existing] });
+
+    await expect(
+      (adapter as any).updateConversation(
+        "conv-1",
+        { title: "Updated" },
+        { expectedUserId: "user-1" },
+      ),
+    ).rejects.toBeInstanceOf(ConversationOwnershipMismatchError);
+
+    expect(
+      mockExecute.mock.calls.some(([input]) =>
+        String(input.sql).includes("UPDATE test_conversations"),
+      ),
+    ).toBe(false);
+  });
+
+  it("adds expectedUserId to deleteConversation mutations", async () => {
+    mockExecute.mockResolvedValueOnce({ rows: [], rowsAffected: 1 });
+
+    await (adapter as any).deleteConversation("conv-1", { expectedUserId: "user-1" });
+
+    const deleteCall = mockExecute.mock.calls.at(-1)?.[0];
+    expect(deleteCall.sql).toContain("DELETE FROM test_conversations WHERE id = ? AND user_id = ?");
+    expect(deleteCall.args).toEqual(["conv-1", "user-1"]);
+  });
+
+  it("rejects guarded deletes when no owned conversation row is affected", async () => {
+    mockExecute.mockResolvedValueOnce({ rows: [], rowsAffected: 0 });
+
+    await expect(
+      (adapter as any).deleteConversation("conv-1", { expectedUserId: "user-1" }),
+    ).rejects.toBeInstanceOf(ConversationOwnershipMismatchError);
+
+    const deleteCall = mockExecute.mock.calls.at(-1)?.[0];
+    expect(deleteCall.sql).toContain("DELETE FROM test_conversations WHERE id = ? AND user_id = ?");
+    expect(deleteCall.args).toEqual(["conv-1", "user-1"]);
+  });
 });
diff --git a/packages/postgres/package.json b/packages/postgres/package.json
index a17bc179c..29d39ea3e 100644
--- a/packages/postgres/package.json
+++ b/packages/postgres/package.json
@@ -31,7 +31,7 @@
   "main": "dist/index.js",
   "module": "dist/index.mjs",
   "peerDependencies": {
-    "@voltagent/core": "^2.0.0",
+    "@voltagent/core": "^2.9.1",
     "ai": "^6.0.0"
   },
   "repository": {
diff --git a/packages/postgres/src/memory-adapter.spec.ts b/packages/postgres/src/memory-adapter.spec.ts
index 0b7a12b0a..d08d4f8aa 100644
--- a/packages/postgres/src/memory-adapter.spec.ts
+++ b/packages/postgres/src/memory-adapter.spec.ts
@@ -268,6 +268,38 @@ describe.sequential("PostgreSQLMemoryAdapter - Core Functionality", () => {
       const deleted = await adapter.getConversation("conv-delete");
       expect(deleted).toBeNull();
     });
+
+    it("adds expectedUserId to updateConversation mutations", async () => {
+      const originalData = createConversationData({ id: "conv-guard", title: "Original" });
+      const tx = mockTransaction();
+      mockGetConversation(originalData);
+      mockResultWith({ ...originalData, title: "Updated" });
+      tx.commit();
+
+      await (adapter as any).updateConversation(
+        "conv-guard",
+        { title: "Updated" },
+        { expectedUserId: "user-1" },
+      );
+
+      const updateCall = mockQuery.mock.calls.find(([sql]) =>
+        String(sql).includes("UPDATE test_conversations"),
+      );
+      expect(updateCall?.[0]).toContain("WHERE id = $3 AND user_id = $4");
+      expect(updateCall?.[1]).toEqual([expect.any(String), "Updated", "conv-guard", "user-1"]);
+    });
+
+    it("adds expectedUserId to deleteConversation mutations", async () => {
+      mockQuery.mockResolvedValueOnce({ rows: [{ id: "conv-delete" }], rowCount: 1 });
+
+      await (adapter as any).deleteConversation("conv-delete", { expectedUserId: "user-1" });
+
+      const deleteCall = mockQuery.mock.calls.find(([sql]) =>
+        String(sql).includes("DELETE FROM test_conversations"),
+      );
+      expect(deleteCall?.[0]).toContain("WHERE id = $1 AND user_id = $2");
+      expect(deleteCall?.[1]).toEqual(["conv-delete", "user-1"]);
+    });
   });
 
   // ============================================================================
diff --git a/packages/postgres/src/memory-adapter.ts b/packages/postgres/src/memory-adapter.ts
index 6e476c330..b85a0a40e 100644
--- a/packages/postgres/src/memory-adapter.ts
+++ b/packages/postgres/src/memory-adapter.ts
@@ -5,9 +5,14 @@
  */
 
 import type { ConnectionOptions } from "node:tls";
-import { ConversationAlreadyExistsError, ConversationNotFoundError } from "@voltagent/core";
+import {
+  ConversationAlreadyExistsError,
+  ConversationNotFoundError,
+  ConversationOwnershipMismatchError,
+} from "@voltagent/core";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -1048,6 +1053,7 @@ export class PostgreSQLMemoryAdapter implements StorageAdapter {
   async updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation> {
     await this.initPromise;
 
@@ -1061,6 +1067,10 @@ export class PostgreSQLMemoryAdapter implements StorageAdapter {
         throw new ConversationNotFoundError(id);
       }
 
+      if (options?.expectedUserId !== undefined && conversation.userId !== options.expectedUserId) {
+        throw new ConversationOwnershipMismatchError(id);
+      }
+
       const now = new Date().toISOString();
       const fieldsToUpdate: string[] = ["updated_at = $1"];
       const params: any[] = [now];
@@ -1085,15 +1095,28 @@ export class PostgreSQLMemoryAdapter implements StorageAdapter {
       }
 
       params.push(id); // WHERE clause
+      const idParam = paramCount;
+      paramCount++;
+
+      let ownerClause = "";
+      if (options?.expectedUserId !== undefined) {
+        ownerClause = ` AND user_id = $${paramCount}`;
+        params.push(options.expectedUserId);
+        paramCount++;
+      }
 
       const result = await client.query(
         `UPDATE ${conversationsTable} 
          SET ${fieldsToUpdate.join(", ")} 
-         WHERE id = $${paramCount}
+         WHERE id = $${idParam}${ownerClause}
          RETURNING *`,
         params,
       );
 
+      if (options?.expectedUserId !== undefined && result.rows.length === 0) {
+        throw new ConversationOwnershipMismatchError(id);
+      }
+
       await client.query("COMMIT");
 
       const row = result.rows[0];
@@ -1117,14 +1140,28 @@ export class PostgreSQLMemoryAdapter implements StorageAdapter {
   /**
    * Delete a conversation
    */
-  async deleteConversation(id: string): Promise<void> {
+  async deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void> {
     await this.initPromise;
 
     const client = await this.pool.connect();
     try {
       const conversationsTable = this.getTableName(`${this.tablePrefix}_conversations`);
 
-      await client.query(`DELETE FROM ${conversationsTable} WHERE id = $1`, [id]);
+      const params: any[] = [id];
+      let ownerClause = "";
+      if (options?.expectedUserId !== undefined) {
+        ownerClause = " AND user_id = $2";
+        params.push(options.expectedUserId);
+      }
+
+      const result = await client.query(
+        `DELETE FROM ${conversationsTable} WHERE id = $1${ownerClause} RETURNING id`,
+        params,
+      );
+
+      if (options?.expectedUserId !== undefined && result.rows.length === 0) {
+        throw new ConversationOwnershipMismatchError(id);
+      }
 
       this.log(`Deleted conversation ${id}`);
     } finally {
diff --git a/packages/server-core/package.json b/packages/server-core/package.json
index a6e0f4d68..e9a84b899 100644
--- a/packages/server-core/package.json
+++ b/packages/server-core/package.json
@@ -4,7 +4,7 @@
   "version": "2.1.19",
   "dependencies": {
     "@modelcontextprotocol/sdk": "^1.12.1",
-    "@voltagent/core": "^2.8.1",
+    "@voltagent/core": "^2.9.1",
     "@voltagent/internal": "^1.0.2",
     "ai": "^6.0.0",
     "jsonwebtoken": "^9.0.2",
@@ -46,7 +46,7 @@
   "main": "dist/index.js",
   "module": "dist/index.mjs",
   "peerDependencies": {
-    "@voltagent/core": "^2.0.0",
+    "@voltagent/core": "^2.9.1",
     "zod": "^3.25.0 || ^4.0.0"
   },
   "repository": {
diff --git a/packages/server-core/src/handlers/memory.handlers.spec.ts b/packages/server-core/src/handlers/memory.handlers.spec.ts
new file mode 100644
index 000000000..2e05ea84f
--- /dev/null
+++ b/packages/server-core/src/handlers/memory.handlers.spec.ts
@@ -0,0 +1,250 @@
+import {
+  ConversationOwnershipMismatchError,
+  InMemoryStorageAdapter,
+  Memory,
+} from "@voltagent/core";
+import type { Agent, Logger, ServerProviderDeps, VoltOpsClient } from "@voltagent/core";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import {
+  handleDeleteMemoryConversation,
+  handleGetMemoryConversation,
+  handleListMemoryConversationMessages,
+  handleListMemoryConversations,
+  handleUpdateMemoryConversation,
+} from "./memory.handlers";
+
+function createAgentWithMemory(agentId: string, agentName: string, memory: Memory): Agent {
+  return {
+    getFullState: () => ({
+      id: agentId,
+      name: agentName,
+      instructions: "",
+      status: "idle",
+      model: "test-model",
+      tools: [],
+      subAgents: [],
+      memory: {},
+    }),
+    getMemory: () => memory,
+  } as unknown as Agent;
+}
+
+function createDepsWithAgents(agents: Agent[]): ServerProviderDeps {
+  const logger: Logger = {
+    trace: vi.fn(),
+    debug: vi.fn(),
+    info: vi.fn(),
+    warn: vi.fn(),
+    error: vi.fn(),
+    fatal: vi.fn(),
+    child: vi.fn().mockReturnThis(),
+    level: "info",
+    silent: vi.fn(),
+  } as unknown as Logger;
+
+  return {
+    agentRegistry: {
+      getAgent: vi.fn((agentId: string) =>
+        agents.find((agent) => agent.getFullState().id === agentId),
+      ),
+      getAllAgents: vi.fn().mockReturnValue(agents),
+      getAgentCount: vi.fn().mockReturnValue(agents.length),
+      removeAgent: vi.fn(),
+      registerAgent: vi.fn(),
+      getGlobalVoltOpsClient: vi.fn().mockReturnValue(undefined as unknown as VoltOpsClient),
+      getGlobalLogger: vi.fn().mockReturnValue(logger),
+    },
+    workflowRegistry: {
+      getWorkflow: vi.fn(),
+      getWorkflowsForApi: vi.fn().mockReturnValue([]),
+      getWorkflowDetailForApi: vi.fn(),
+      getWorkflowCount: vi.fn().mockReturnValue(0),
+      on: vi.fn(),
+      off: vi.fn(),
+      activeExecutions: new Map(),
+      resumeSuspendedWorkflow: vi.fn(),
+    },
+    triggerRegistry: {
+      list: vi.fn().mockReturnValue([]),
+      register: vi.fn(),
+      registerMany: vi.fn(),
+      get: vi.fn(),
+      getByPath: vi.fn(),
+      unregister: vi.fn(),
+      clear: vi.fn(),
+    } as any,
+    logger,
+  } as unknown as ServerProviderDeps;
+}
+
+describe("memory handlers ownership checks", () => {
+  let memory: Memory;
+  let deps: ServerProviderDeps;
+  const agentId = "agent-1";
+  const ownerUserId = "user-alice";
+  const otherUserId = "user-bob";
+  const conversationId = "conv-private";
+  const otherConversationId = "conv-bob";
+
+  beforeEach(async () => {
+    memory = new Memory({
+      storage: new InMemoryStorageAdapter(),
+    });
+
+    await memory.createConversation({
+      id: conversationId,
+      resourceId: agentId,
+      userId: ownerUserId,
+      title: "Alice Private",
+      metadata: {},
+    });
+
+    await memory.createConversation({
+      id: otherConversationId,
+      resourceId: agentId,
+      userId: otherUserId,
+      title: "Bob Private",
+      metadata: {},
+    });
+
+    await memory.addMessage(
+      {
+        id: "msg-1",
+        role: "user",
+        parts: [{ type: "text", text: "Confidential" }],
+      },
+      ownerUserId,
+      conversationId,
+    );
+
+    deps = createDepsWithAgents([createAgentWithMemory(agentId, "Agent One", memory)]);
+  });
+
+  it("rejects reading a conversation owned by a different authenticated user", async () => {
+    const result = await handleGetMemoryConversation(deps, conversationId, {
+      agentId,
+      requestingUserId: otherUserId,
+    });
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+  });
+
+  it("rejects reading a conversation when the authenticated identity is empty", async () => {
+    const result = await handleGetMemoryConversation(deps, conversationId, {
+      agentId,
+      requestingUserId: "",
+    });
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+  });
+
+  it("lists conversations for the authenticated user instead of a client-supplied userId", async () => {
+    const result = await handleListMemoryConversations(deps, {
+      agentId,
+      userId: ownerUserId,
+      requestingUserId: otherUserId,
+    });
+
+    expect(result.success).toBe(true);
+    if (!result.success) return;
+    expect(result.data.total).toBe(1);
+    expect(result.data.conversations).toHaveLength(1);
+    expect(result.data.conversations[0]?.id).toBe(otherConversationId);
+    expect(result.data.conversations[0]?.userId).toBe(otherUserId);
+  });
+
+  it("rejects listing conversations when the authenticated identity is empty", async () => {
+    const result = await handleListMemoryConversations(deps, {
+      agentId,
+      userId: ownerUserId,
+      requestingUserId: "",
+    });
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+  });
+
+  it("rejects listing messages for a conversation owned by a different authenticated user", async () => {
+    const result = await handleListMemoryConversationMessages(deps, conversationId, {
+      agentId,
+      requestingUserId: otherUserId,
+    });
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+  });
+
+  it("rejects updating a conversation owned by a different authenticated user", async () => {
+    const result = await handleUpdateMemoryConversation(deps, conversationId, {
+      agentId,
+      requestingUserId: otherUserId,
+      title: "Bob title",
+    } as any);
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+
+    const conversation = await memory.getConversation(conversationId);
+    expect(conversation?.title).toBe("Alice Private");
+  });
+
+  it("returns forbidden when a guarded storage update no longer affects the owner", async () => {
+    const updateSpy = vi
+      .spyOn(memory, "updateConversation")
+      .mockRejectedValueOnce(new ConversationOwnershipMismatchError(conversationId));
+
+    const result = await handleUpdateMemoryConversation(deps, conversationId, {
+      agentId,
+      requestingUserId: ownerUserId,
+      title: "Updated title",
+    });
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+    expect(updateSpy).toHaveBeenCalledWith(
+      conversationId,
+      { title: "Updated title" },
+      { expectedUserId: ownerUserId },
+    );
+  });
+
+  it("rejects deleting a conversation owned by a different authenticated user", async () => {
+    const result = await handleDeleteMemoryConversation(deps, conversationId, {
+      agentId,
+      requestingUserId: otherUserId,
+    });
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+
+    await expect(memory.getConversation(conversationId)).resolves.not.toBeNull();
+  });
+
+  it("returns forbidden when a guarded storage delete no longer affects the owner", async () => {
+    const deleteSpy = vi
+      .spyOn(memory, "deleteConversation")
+      .mockRejectedValueOnce(new ConversationOwnershipMismatchError(conversationId));
+
+    const result = await handleDeleteMemoryConversation(deps, conversationId, {
+      agentId,
+      requestingUserId: ownerUserId,
+    });
+
+    expect(result.success).toBe(false);
+    expect(result.httpStatus).toBe(403);
+    expect(deleteSpy).toHaveBeenCalledWith(conversationId, { expectedUserId: ownerUserId });
+  });
+
+  it("allows the owning authenticated user to manage the conversation", async () => {
+    const result = await handleGetMemoryConversation(deps, conversationId, {
+      agentId,
+      requestingUserId: ownerUserId,
+    });
+
+    expect(result.success).toBe(true);
+    if (!result.success) return;
+    expect(result.data.conversation.userId).toBe(ownerUserId);
+  });
+});
diff --git a/packages/server-core/src/handlers/memory.handlers.ts b/packages/server-core/src/handlers/memory.handlers.ts
index 31401f9c1..b58308a59 100644
--- a/packages/server-core/src/handlers/memory.handlers.ts
+++ b/packages/server-core/src/handlers/memory.handlers.ts
@@ -3,6 +3,7 @@ import {
   type Conversation,
   ConversationAlreadyExistsError,
   ConversationNotFoundError,
+  ConversationOwnershipMismatchError,
   EmbeddingAdapterNotConfiguredError,
   type Memory,
   type ServerProviderDeps,
@@ -106,6 +107,25 @@ function buildErrorResponse(error: unknown): ApiResponse {
   };
 }
 
+function buildForbiddenResponse(): ApiResponse {
+  return {
+    success: false,
+    error: "Forbidden",
+    httpStatus: 403,
+  };
+}
+
+function assertConversationOwner(
+  conversation: Conversation,
+  requestingUserId?: string,
+): ApiResponse | null {
+  if (requestingUserId !== undefined && conversation.userId !== requestingUserId) {
+    return buildForbiddenResponse();
+  }
+
+  return null;
+}
+
 export async function handleListMemoryConversations(
   deps: ServerProviderDeps,
   query: {
@@ -116,6 +136,7 @@ export async function handleListMemoryConversations(
     offset?: number;
     orderBy?: "created_at" | "updated_at" | "title";
     orderDirection?: "ASC" | "DESC";
+    requestingUserId?: string;
   },
 ): Promise<
   ApiResponse<{ conversations: Conversation[]; total: number; limit: number; offset: number }>
@@ -130,10 +151,15 @@ export async function handleListMemoryConversations(
       };
     }
 
+    if (query.requestingUserId !== undefined && !query.requestingUserId) {
+      return buildForbiddenResponse();
+    }
+
     const resourceId = query.resourceId ?? resolved.resourceId;
+    const userId = query.requestingUserId ?? query.userId;
     const [conversations, total] = await Promise.all([
       resolved.memory.queryConversations({
-        userId: query.userId,
+        userId,
         resourceId,
         limit: query.limit,
         offset: query.offset,
@@ -141,7 +167,7 @@ export async function handleListMemoryConversations(
         orderDirection: query.orderDirection,
       }),
       resolved.memory.countConversations({
-        userId: query.userId,
+        userId,
         resourceId,
       }),
     ]);
@@ -163,7 +189,7 @@ export async function handleListMemoryConversations(
 export async function handleGetMemoryConversation(
   deps: ServerProviderDeps,
   conversationId: string,
-  query: { agentId?: string },
+  query: { agentId?: string; requestingUserId?: string },
 ): Promise<ApiResponse<{ conversation: Conversation }>> {
   try {
     const resolved = resolveMemory(deps, query.agentId);
@@ -184,6 +210,11 @@ export async function handleGetMemoryConversation(
       };
     }
 
+    const ownershipError = assertConversationOwner(conversation, query.requestingUserId);
+    if (ownershipError) {
+      return ownershipError;
+    }
+
     return {
       success: true,
       data: { conversation },
@@ -203,6 +234,7 @@ export async function handleListMemoryConversationMessages(
     after?: Date;
     roles?: string[];
     userId?: string;
+    requestingUserId?: string;
   },
 ): Promise<ApiResponse<{ conversation: Conversation; messages: UIMessage[] }>> {
   try {
@@ -224,6 +256,11 @@ export async function handleListMemoryConversationMessages(
       };
     }
 
+    const ownershipError = assertConversationOwner(conversation, query.requestingUserId);
+    if (ownershipError) {
+      return ownershipError;
+    }
+
     const userId = query.userId ?? conversation.userId;
     const messages = await resolved.memory.getMessages(userId, conversationId, {
       limit: query.limit,
@@ -498,6 +535,7 @@ export async function handleUpdateMemoryConversation(
     agentId?: string;
     resourceId?: string;
     userId?: string;
+    requestingUserId?: string;
     title?: string;
     metadata?: Record<string, unknown>;
   },
@@ -534,7 +572,27 @@ export async function handleUpdateMemoryConversation(
       };
     }
 
-    const conversation = await resolved.memory.updateConversation(conversationId, updates);
+    const existingConversation = await resolved.memory.getConversation(conversationId);
+    if (!existingConversation) {
+      return {
+        success: false,
+        error: "Conversation not found",
+        httpStatus: 404,
+      };
+    }
+
+    const ownershipError = assertConversationOwner(existingConversation, body.requestingUserId);
+    if (ownershipError) {
+      return ownershipError;
+    }
+
+    const mutationOptions =
+      body.requestingUserId !== undefined ? { expectedUserId: body.requestingUserId } : undefined;
+    const conversation = await resolved.memory.updateConversation(
+      conversationId,
+      updates,
+      mutationOptions,
+    );
     return {
       success: true,
       data: { conversation },
@@ -547,6 +605,9 @@ export async function handleUpdateMemoryConversation(
         httpStatus: 404,
       };
     }
+    if (error instanceof ConversationOwnershipMismatchError) {
+      return buildForbiddenResponse();
+    }
     return buildErrorResponse(error);
   }
 }
@@ -554,7 +615,7 @@ export async function handleUpdateMemoryConversation(
 export async function handleDeleteMemoryConversation(
   deps: ServerProviderDeps,
   conversationId: string,
-  query: { agentId?: string },
+  query: { agentId?: string; requestingUserId?: string },
 ): Promise<ApiResponse<{ deleted: boolean }>> {
   try {
     const resolved = resolveMemory(deps, query.agentId);
@@ -566,7 +627,23 @@ export async function handleDeleteMemoryConversation(
       };
     }
 
-    await resolved.memory.deleteConversation(conversationId);
+    const conversation = await resolved.memory.getConversation(conversationId);
+    if (!conversation) {
+      return {
+        success: false,
+        error: "Conversation not found",
+        httpStatus: 404,
+      };
+    }
+
+    const ownershipError = assertConversationOwner(conversation, query.requestingUserId);
+    if (ownershipError) {
+      return ownershipError;
+    }
+
+    const mutationOptions =
+      query.requestingUserId !== undefined ? { expectedUserId: query.requestingUserId } : undefined;
+    await resolved.memory.deleteConversation(conversationId, mutationOptions);
     return {
       success: true,
       data: { deleted: true },
@@ -579,6 +656,9 @@ export async function handleDeleteMemoryConversation(
         httpStatus: 404,
       };
     }
+    if (error instanceof ConversationOwnershipMismatchError) {
+      return buildForbiddenResponse();
+    }
     return buildErrorResponse(error);
   }
 }
diff --git a/packages/server-elysia/src/auth/middleware.ts b/packages/server-elysia/src/auth/middleware.ts
index e94779049..04cfadeab 100644
--- a/packages/server-elysia/src/auth/middleware.ts
+++ b/packages/server-elysia/src/auth/middleware.ts
@@ -8,6 +8,16 @@ import {
 } from "@voltagent/server-core";
 import type { Context } from "elysia";
 
+const requestAuthenticatedUsers = new WeakMap<Request, unknown>();
+
+export function setRequestAuthenticatedUser(request: Request, user: unknown): void {
+  requestAuthenticatedUsers.set(request, user);
+}
+
+export function getRequestAuthenticatedUser(request: Request): unknown {
+  return requestAuthenticatedUsers.get(request);
+}
+
 /**
  * Create authentication middleware for Elysia
  * This middleware handles both authentication and user context injection
@@ -81,6 +91,7 @@ export function createAuthMiddleware(authProvider: AuthProvider<Request>) {
 
       // Store user in store for route handlers to access
       store.authenticatedUser = user;
+      setRequestAuthenticatedUser(request, user);
 
       // Also inject user context into request body for agent/workflow execution
       injectUserContext(request, user);
@@ -165,6 +176,7 @@ export function createAuthNextMiddleware(
 
       // Store user in store for route handlers to access
       store.authenticatedUser = user;
+      setRequestAuthenticatedUser(request, user);
 
       // Also inject user context into request body for agent/workflow execution
       injectUserContext(request, user);
diff --git a/packages/server-elysia/src/routes/memory.routes.spec.ts b/packages/server-elysia/src/routes/memory.routes.spec.ts
new file mode 100644
index 000000000..7aff89041
--- /dev/null
+++ b/packages/server-elysia/src/routes/memory.routes.spec.ts
@@ -0,0 +1,65 @@
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+vi.mock("@voltagent/server-core", async (importOriginal) => {
+  const actual = await importOriginal<typeof import("@voltagent/server-core")>();
+  return {
+    ...actual,
+    handleListMemoryConversations: vi.fn().mockResolvedValue({
+      success: true,
+      data: { conversations: [], total: 0, limit: 0, offset: 0 },
+    }),
+  };
+});
+
+import { MEMORY_ROUTES, handleListMemoryConversations } from "@voltagent/server-core";
+import { setRequestAuthenticatedUser } from "../auth/middleware";
+import { registerMemoryRoutes } from "./memory.routes";
+
+type RouteHandler = (context: Record<string, unknown>) => Promise<unknown>;
+
+function createRouteCollector() {
+  const handlers = new Map<string, RouteHandler>();
+  const app: Record<string, ReturnType<typeof vi.fn>> = {};
+
+  for (const method of ["get", "post", "patch", "delete"] as const) {
+    app[method] = vi.fn((path: string, handler: RouteHandler) => {
+      handlers.set(`${method}:${path}`, handler);
+      return app;
+    });
+  }
+
+  return { app, handlers };
+}
+
+describe("Elysia memory routes", () => {
+  const deps = {} as any;
+  const logger = { trace: vi.fn(), warn: vi.fn() } as any;
+
+  beforeEach(() => {
+    vi.clearAllMocks();
+  });
+
+  it("passes the request authenticated user to list-conversations", async () => {
+    const { app, handlers } = createRouteCollector();
+    registerMemoryRoutes(app as any, deps, logger);
+    const handler = handlers.get(`get:${MEMORY_ROUTES.listConversations.path}`);
+    expect(handler).toBeDefined();
+
+    const request = new Request("http://localhost/api/memory/conversations");
+    setRequestAuthenticatedUser(request, { id: "user-bob" });
+    await handler?.({
+      query: { agentId: "agent-1", userId: "user-alice" },
+      request,
+      set: {},
+    });
+
+    expect(handleListMemoryConversations).toHaveBeenCalledWith(
+      deps,
+      expect.objectContaining({
+        agentId: "agent-1",
+        userId: "user-alice",
+        requestingUserId: "user-bob",
+      }),
+    );
+  });
+});
diff --git a/packages/server-elysia/src/routes/memory.routes.ts b/packages/server-elysia/src/routes/memory.routes.ts
index 17e92db06..7a103878c 100644
--- a/packages/server-elysia/src/routes/memory.routes.ts
+++ b/packages/server-elysia/src/routes/memory.routes.ts
@@ -16,6 +16,7 @@ import {
   handleUpdateMemoryWorkingMemory,
 } from "@voltagent/server-core";
 import type { Elysia } from "elysia";
+import { getRequestAuthenticatedUser } from "../auth/middleware";
 
 function parseNumber(value?: string | number): number | undefined {
   if (value === undefined || value === null) {
@@ -41,6 +42,20 @@ function parseDate(value?: string): Date | undefined {
   return Number.isNaN(parsed.getTime()) ? undefined : parsed;
 }
 
+function getAuthenticatedUserId(request: Request): string | undefined {
+  const user = getRequestAuthenticatedUser(request) as
+    | { id?: unknown; sub?: unknown }
+    | null
+    | undefined;
+  if (typeof user?.id === "string") {
+    return user.id;
+  }
+  if (typeof user?.sub === "string") {
+    return user.sub;
+  }
+  return undefined;
+}
+
 type MemoryRoutesCompat = typeof MEMORY_ROUTES & {
   getWorkingMemory?: { path: string };
 };
@@ -54,12 +69,13 @@ const memoryWorkingMemoryPath =
  * Register memory routes
  */
 export function registerMemoryRoutes(app: Elysia, deps: ServerProviderDeps, logger: Logger) {
-  app.get(MEMORY_ROUTES.listConversations.path, async ({ query, set }) => {
+  app.get(MEMORY_ROUTES.listConversations.path, async ({ query, request, set }) => {
     logger.trace("GET /api/memory/conversations - fetching conversations", { query });
     const response = await handleListMemoryConversations(deps, {
       agentId: query.agentId as string | undefined,
       resourceId: query.resourceId as string | undefined,
       userId: query.userId as string | undefined,
+      requestingUserId: getAuthenticatedUserId(request),
       limit: parseNumber(query.limit as string | number | undefined),
       offset: parseNumber(query.offset as string | number | undefined),
       orderBy: query.orderBy as "created_at" | "updated_at" | "title" | undefined,
@@ -69,17 +85,18 @@ export function registerMemoryRoutes(app: Elysia, deps: ServerProviderDeps, logg
     return response;
   });
 
-  app.get(MEMORY_ROUTES.getConversation.path, async ({ params, query, set }) => {
+  app.get(MEMORY_ROUTES.getConversation.path, async ({ params, query, request, set }) => {
     const conversationId = params.conversationId;
     logger.trace(`GET /api/memory/conversations/${conversationId} - fetching conversation`);
     const response = await handleGetMemoryConversation(deps, conversationId, {
       agentId: query.agentId as string | undefined,
+      requestingUserId: getAuthenticatedUserId(request),
     });
     set.status = response.success ? 200 : (response.httpStatus ?? 500);
     return response;
   });
 
-  app.get(MEMORY_ROUTES.listMessages.path, async ({ params, query, set }) => {
+  app.get(MEMORY_ROUTES.listMessages.path, async ({ params, query, request, set }) => {
     const conversationId = params.conversationId;
     logger.trace(`GET /api/memory/conversations/${conversationId}/messages - fetching messages`, {
       query,
@@ -91,6 +108,7 @@ export function registerMemoryRoutes(app: Elysia, deps: ServerProviderDeps, logg
       after: parseDate(query.after as string | undefined),
       roles: query.roles ? String(query.roles).split(",") : undefined,
       userId: query.userId as string | undefined,
+      requestingUserId: getAuthenticatedUserId(request),
     });
     set.status = response.success ? 200 : (response.httpStatus ?? 500);
     return response;
@@ -135,23 +153,28 @@ export function registerMemoryRoutes(app: Elysia, deps: ServerProviderDeps, logg
     return response;
   });
 
-  app.patch(MEMORY_ROUTES.updateConversation.path, async ({ params, body, query, set }) => {
-    const conversationId = params.conversationId;
-    const payload = body as Record<string, unknown> | undefined;
-    logger.trace(`PATCH /api/memory/conversations/${conversationId} - updating conversation`);
-    const response = await handleUpdateMemoryConversation(deps, conversationId, {
-      ...(payload ?? {}),
-      agentId: (payload?.agentId as string | undefined) ?? (query.agentId as string | undefined),
-    });
-    set.status = response.success ? 200 : (response.httpStatus ?? 500);
-    return response;
-  });
-
-  app.delete(MEMORY_ROUTES.deleteConversation.path, async ({ params, query, set }) => {
+  app.patch(
+    MEMORY_ROUTES.updateConversation.path,
+    async ({ params, body, query, request, set }) => {
+      const conversationId = params.conversationId;
+      const payload = body as Record<string, unknown> | undefined;
+      logger.trace(`PATCH /api/memory/conversations/${conversationId} - updating conversation`);
+      const response = await handleUpdateMemoryConversation(deps, conversationId, {
+        ...(payload ?? {}),
+        agentId: (payload?.agentId as string | undefined) ?? (query.agentId as string | undefined),
+        requestingUserId: getAuthenticatedUserId(request),
+      });
+      set.status = response.success ? 200 : (response.httpStatus ?? 500);
+      return response;
+    },
+  );
+
+  app.delete(MEMORY_ROUTES.deleteConversation.path, async ({ params, query, request, set }) => {
     const conversationId = params.conversationId;
     logger.trace(`DELETE /api/memory/conversations/${conversationId} - deleting conversation`);
     const response = await handleDeleteMemoryConversation(deps, conversationId, {
       agentId: query.agentId as string | undefined,
+      requestingUserId: getAuthenticatedUserId(request),
     });
     set.status = response.success ? 200 : (response.httpStatus ?? 500);
     return response;
diff --git a/packages/server-hono/src/routes/memory.routes.spec.ts b/packages/server-hono/src/routes/memory.routes.spec.ts
new file mode 100644
index 000000000..08ae13146
--- /dev/null
+++ b/packages/server-hono/src/routes/memory.routes.spec.ts
@@ -0,0 +1,66 @@
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+vi.mock("@voltagent/server-core", async (importOriginal) => {
+  const actual = await importOriginal<typeof import("@voltagent/server-core")>();
+  return {
+    ...actual,
+    handleListMemoryConversations: vi.fn().mockResolvedValue({
+      success: true,
+      data: { conversations: [], total: 0, limit: 0, offset: 0 },
+    }),
+  };
+});
+
+import { MEMORY_ROUTES, handleListMemoryConversations } from "@voltagent/server-core";
+import { registerMemoryRoutes } from "./memory.routes";
+
+type RouteHandler = (context: Record<string, any>) => Promise<unknown>;
+
+function createRouteCollector() {
+  const handlers = new Map<string, RouteHandler>();
+  const app: Record<string, ReturnType<typeof vi.fn>> = {};
+
+  for (const method of ["get", "post", "patch", "delete"] as const) {
+    app[method] = vi.fn((path: string, handler: RouteHandler) => {
+      handlers.set(`${method}:${path}`, handler);
+      return app;
+    });
+  }
+
+  return { app, handlers };
+}
+
+describe("Hono memory routes", () => {
+  const deps = {} as any;
+  const logger = { trace: vi.fn(), warn: vi.fn() } as any;
+
+  beforeEach(() => {
+    vi.clearAllMocks();
+  });
+
+  it("passes the authenticated user to list-conversations", async () => {
+    const { app, handlers } = createRouteCollector();
+    registerMemoryRoutes(app as any, deps, logger);
+    const handler = handlers.get(`get:${MEMORY_ROUTES.listConversations.path}`);
+    expect(handler).toBeDefined();
+
+    const context = {
+      req: {
+        query: () => ({ agentId: "agent-1", userId: "user-alice" }),
+      },
+      get: vi.fn((key: string) => (key === "authenticatedUser" ? { sub: "user-bob" } : undefined)),
+      json: vi.fn((response: unknown, status: number) => ({ response, status })),
+    };
+
+    await handler?.(context);
+
+    expect(handleListMemoryConversations).toHaveBeenCalledWith(
+      deps,
+      expect.objectContaining({
+        agentId: "agent-1",
+        userId: "user-alice",
+        requestingUserId: "user-bob",
+      }),
+    );
+  });
+});
diff --git a/packages/server-hono/src/routes/memory.routes.ts b/packages/server-hono/src/routes/memory.routes.ts
index 44e4ff58e..fe525f6eb 100644
--- a/packages/server-hono/src/routes/memory.routes.ts
+++ b/packages/server-hono/src/routes/memory.routes.ts
@@ -41,6 +41,17 @@ function parseDate(value?: string): Date | undefined {
   return Number.isNaN(parsed.getTime()) ? undefined : parsed;
 }
 
+function getAuthenticatedUserId(c: { get?: (key: string) => unknown }): string | undefined {
+  const user = c.get?.("authenticatedUser") as { id?: unknown; sub?: unknown } | null | undefined;
+  if (typeof user?.id === "string") {
+    return user.id;
+  }
+  if (typeof user?.sub === "string") {
+    return user.sub;
+  }
+  return undefined;
+}
+
 const orderByAllowlist = new Set(["created_at", "updated_at", "title"]);
 
 function parseOrderBy(value?: string): "created_at" | "updated_at" | "title" | undefined {
@@ -85,6 +96,7 @@ export function registerMemoryRoutes(
       agentId: query.agentId,
       resourceId: query.resourceId,
       userId: query.userId,
+      requestingUserId: getAuthenticatedUserId(c),
       limit: parseNumber(query.limit),
       offset: parseNumber(query.offset),
       orderBy: parseOrderBy(query.orderBy),
@@ -100,6 +112,7 @@ export function registerMemoryRoutes(
     logger.trace(`GET /api/memory/conversations/${conversationId} - fetching conversation`);
     const response = await handleGetMemoryConversation(deps, conversationId, {
       agentId: query.agentId,
+      requestingUserId: getAuthenticatedUserId(c),
     });
     return c.json(response, response.success ? 200 : (response.httpStatus ?? 500));
   });
@@ -117,6 +130,7 @@ export function registerMemoryRoutes(
       after: parseDate(query.after),
       roles: query.roles ? query.roles.split(",") : undefined,
       userId: query.userId,
+      requestingUserId: getAuthenticatedUserId(c),
     });
     return c.json(response, response.success ? 200 : (response.httpStatus ?? 500));
   });
@@ -186,6 +200,7 @@ export function registerMemoryRoutes(
     const response = await handleUpdateMemoryConversation(deps, conversationId, {
       ...body,
       agentId: body?.agentId ?? query.agentId,
+      requestingUserId: getAuthenticatedUserId(c),
     });
     return c.json(response, response.success ? 200 : (response.httpStatus ?? 500));
   });
@@ -196,6 +211,7 @@ export function registerMemoryRoutes(
     logger.trace(`DELETE /api/memory/conversations/${conversationId} - deleting conversation`);
     const response = await handleDeleteMemoryConversation(deps, conversationId, {
       agentId: query.agentId,
+      requestingUserId: getAuthenticatedUserId(c),
     });
     return c.json(response, response.success ? 200 : (response.httpStatus ?? 500));
   });
diff --git a/packages/supabase/package.json b/packages/supabase/package.json
index bb9f3fb25..d544649de 100644
--- a/packages/supabase/package.json
+++ b/packages/supabase/package.json
@@ -32,7 +32,7 @@
   "main": "dist/index.js",
   "module": "dist/index.mjs",
   "peerDependencies": {
-    "@voltagent/core": "^2.0.0",
+    "@voltagent/core": "^2.9.1",
     "@voltagent/logger": "^2.0.0",
     "ai": "^6.0.0"
   },
diff --git a/packages/supabase/src/memory-adapter.spec.ts b/packages/supabase/src/memory-adapter.spec.ts
index fee5cc645..3c41ebbb8 100644
--- a/packages/supabase/src/memory-adapter.spec.ts
+++ b/packages/supabase/src/memory-adapter.spec.ts
@@ -229,6 +229,41 @@ describe.sequential("SupabaseMemoryAdapter - Core Functionality", () => {
       expect(mockClient.from).toHaveBeenCalledWith("voltagent_memory_conversations");
     });
 
+    it("adds expectedUserId to updateConversation mutations", async () => {
+      const existingRow = {
+        id: "conv-1",
+        resource_id: "resource-1",
+        user_id: "user-1",
+        title: "Old Title",
+        metadata: {},
+        created_at: new Date().toISOString(),
+        updated_at: new Date().toISOString(),
+      };
+      const updatedRow = { ...existingRow, title: "Updated Title" };
+
+      supabaseMock.queue("voltagent_memory_conversations", ok(existingRow), ok(updatedRow));
+
+      await (adapter as any).updateConversation(
+        "conv-1",
+        { title: "Updated Title" },
+        { expectedUserId: "user-1" },
+      );
+
+      const updateBuilder = supabaseMock.getHistory("voltagent_memory_conversations")[1];
+      expect(updateBuilder.eq).toHaveBeenCalledWith("id", "conv-1");
+      expect(updateBuilder.eq).toHaveBeenCalledWith("user_id", "user-1");
+    });
+
+    it("adds expectedUserId to deleteConversation mutations", async () => {
+      supabaseMock.queue("voltagent_memory_conversations", ok({ id: "conv-1" }));
+
+      await (adapter as any).deleteConversation("conv-1", { expectedUserId: "user-1" });
+
+      const deleteBuilder = supabaseMock.getHistory("voltagent_memory_conversations")[0];
+      expect(deleteBuilder.eq).toHaveBeenCalledWith("id", "conv-1");
+      expect(deleteBuilder.eq).toHaveBeenCalledWith("user_id", "user-1");
+    });
+
     it("should get conversations by resource ID", async () => {
       const dbRows = [
         {
diff --git a/packages/supabase/src/memory-adapter.ts b/packages/supabase/src/memory-adapter.ts
index 7ce94542f..c59c10901 100644
--- a/packages/supabase/src/memory-adapter.ts
+++ b/packages/supabase/src/memory-adapter.ts
@@ -5,9 +5,14 @@
  */
 
 import { type SupabaseClient, createClient } from "@supabase/supabase-js";
-import { ConversationAlreadyExistsError, ConversationNotFoundError } from "@voltagent/core";
+import {
+  ConversationAlreadyExistsError,
+  ConversationNotFoundError,
+  ConversationOwnershipMismatchError,
+} from "@voltagent/core";
 import type {
   Conversation,
+  ConversationMutationOptions,
   ConversationQueryOptions,
   ConversationStepRecord,
   CreateConversationInput,
@@ -1066,6 +1071,7 @@ END OF MIGRATION SQL
   async updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation> {
     await this.initialize();
 
@@ -1075,6 +1081,10 @@ END OF MIGRATION SQL
       throw new ConversationNotFoundError(id);
     }
 
+    if (options?.expectedUserId !== undefined && conversation.userId !== options.expectedUserId) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
     const now = new Date().toISOString();
     const updateData: any = { updated_at: now };
 
@@ -1090,14 +1100,18 @@ END OF MIGRATION SQL
       updateData.metadata = updates.metadata;
     }
 
-    const { data, error } = await this.client
-      .from(conversationsTable)
-      .update(updateData)
-      .eq("id", id)
-      .select()
-      .single();
+    let query = this.client.from(conversationsTable).update(updateData).eq("id", id);
+
+    if (options?.expectedUserId !== undefined) {
+      query = query.eq("user_id", options.expectedUserId);
+    }
+
+    const { data, error } = await query.select().single();
 
     if (error) {
+      if (options?.expectedUserId !== undefined && error.code === "PGRST116") {
+        throw new ConversationOwnershipMismatchError(id);
+      }
       throw new Error(`Failed to update conversation: ${error.message}`);
     }
 
@@ -1115,12 +1129,31 @@ END OF MIGRATION SQL
   /**
    * Delete a conversation
    */
-  async deleteConversation(id: string): Promise<void> {
+  async deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void> {
     await this.initialize();
 
     const conversationsTable = `${this.baseTableName}_conversations`;
 
-    const { error } = await this.client.from(conversationsTable).delete().eq("id", id);
+    const deleteQuery = this.client.from(conversationsTable).delete().eq("id", id);
+
+    if (options?.expectedUserId !== undefined) {
+      const { error } = await deleteQuery
+        .eq("user_id", options.expectedUserId)
+        .select("id")
+        .single();
+
+      if (error) {
+        if (error.code === "PGRST116") {
+          throw new ConversationOwnershipMismatchError(id);
+        }
+        throw new Error(`Failed to delete conversation: ${error.message}`);
+      }
+
+      this.log(`Deleted conversation ${id}`);
+      return;
+    }
+
+    const { error } = await deleteQuery;
 
     if (error) {
       throw new Error(`Failed to delete conversation: ${error.message}`);
diff --git a/packages/voltagent-memory/package.json b/packages/voltagent-memory/package.json
index 1a87d6e7a..c9ecf875e 100644
--- a/packages/voltagent-memory/package.json
+++ b/packages/voltagent-memory/package.json
@@ -29,7 +29,7 @@
   "main": "dist/index.js",
   "module": "dist/index.mjs",
   "peerDependencies": {
-    "@voltagent/core": "^2.0.0",
+    "@voltagent/core": "^2.9.1",
     "ai": "^6.0.0"
   },
   "repository": {
diff --git a/packages/voltagent-memory/src/index.spec.ts b/packages/voltagent-memory/src/index.spec.ts
new file mode 100644
index 000000000..3682ef9bf
--- /dev/null
+++ b/packages/voltagent-memory/src/index.spec.ts
@@ -0,0 +1,153 @@
+import { ConversationOwnershipMismatchError } from "@voltagent/core";
+import { describe, expect, it, vi } from "vitest";
+import { ManagedMemoryAdapter } from "./index";
+
+function createConversation(userId: string) {
+  return {
+    id: "conv-1",
+    userId,
+    resourceId: "agent-1",
+    title: "Private",
+    metadata: {},
+    createdAt: "2024-01-01T00:00:00.000Z",
+    updatedAt: "2024-01-01T00:00:00.000Z",
+  };
+}
+
+function createVoltOpsClient() {
+  const conversations = {
+    create: vi.fn(),
+    get: vi.fn(),
+    query: vi.fn(),
+    update: vi.fn(),
+    delete: vi.fn(),
+  };
+
+  return {
+    client: {
+      hasValidKeys: vi.fn(() => true),
+      listManagedMemoryDatabases: vi.fn().mockResolvedValue([
+        {
+          id: "db-1",
+          name: "primary",
+          region: "test",
+          connection: {},
+        },
+      ]),
+      managedMemory: {
+        conversations,
+        messages: {
+          add: vi.fn(),
+          addBatch: vi.fn(),
+          list: vi.fn(),
+          clear: vi.fn(),
+          delete: vi.fn(),
+        },
+        workingMemory: {
+          get: vi.fn(),
+          set: vi.fn(),
+          delete: vi.fn(),
+        },
+        workflowStates: {
+          get: vi.fn(),
+          set: vi.fn(),
+          update: vi.fn(),
+          list: vi.fn(),
+          query: vi.fn(),
+          listSuspended: vi.fn(),
+        },
+        steps: {
+          save: vi.fn(),
+          list: vi.fn(),
+        },
+        vectors: {
+          store: vi.fn(),
+          storeBatch: vi.fn(),
+          search: vi.fn(),
+          get: vi.fn(),
+          delete: vi.fn(),
+          deleteBatch: vi.fn(),
+          clear: vi.fn(),
+          count: vi.fn(),
+        },
+      },
+    } as any,
+    conversations,
+  };
+}
+
+describe("ManagedMemoryAdapter conversation ownership guards", () => {
+  it("rejects guarded updates before delegating when the owner does not match", async () => {
+    const { client, conversations } = createVoltOpsClient();
+    conversations.get.mockResolvedValue(createConversation("user-2"));
+
+    const adapter = new ManagedMemoryAdapter({ databaseId: "db-1", voltOpsClient: client });
+
+    await expect(
+      adapter.updateConversation("conv-1", { title: "Updated" }, { expectedUserId: "user-1" }),
+    ).rejects.toBeInstanceOf(ConversationOwnershipMismatchError);
+
+    expect(conversations.update).not.toHaveBeenCalled();
+  });
+
+  it("delegates guarded updates when the owner matches", async () => {
+    const { client, conversations } = createVoltOpsClient();
+    conversations.get.mockResolvedValue(createConversation("user-1"));
+    conversations.update.mockResolvedValue({ ...createConversation("user-1"), title: "Updated" });
+
+    const adapter = new ManagedMemoryAdapter({ databaseId: "db-1", voltOpsClient: client });
+
+    await expect(
+      adapter.updateConversation("conv-1", { title: "Updated" }, { expectedUserId: "user-1" }),
+    ).resolves.toMatchObject({ title: "Updated" });
+
+    expect(conversations.update).toHaveBeenCalledWith("db-1", {
+      conversationId: "conv-1",
+      updates: { title: "Updated" },
+      expectedUserId: "user-1",
+    });
+  });
+
+  it("checks ownership before delegated deletes", async () => {
+    const { client, conversations } = createVoltOpsClient();
+    conversations.get.mockResolvedValue(createConversation("user-1"));
+    conversations.delete.mockResolvedValue(undefined);
+
+    const adapter = new ManagedMemoryAdapter({ databaseId: "db-1", voltOpsClient: client });
+
+    await expect(
+      adapter.deleteConversation("conv-1", { expectedUserId: "user-1" }),
+    ).resolves.toBeUndefined();
+
+    expect(conversations.get).toHaveBeenCalledWith("db-1", "conv-1");
+    expect(conversations.delete).toHaveBeenCalledWith("db-1", "conv-1", {
+      expectedUserId: "user-1",
+    });
+  });
+
+  it("rejects guarded deletes before delegating when the owner does not match", async () => {
+    const { client, conversations } = createVoltOpsClient();
+    conversations.get.mockResolvedValue(createConversation("user-2"));
+
+    const adapter = new ManagedMemoryAdapter({ databaseId: "db-1", voltOpsClient: client });
+
+    await expect(
+      adapter.deleteConversation("conv-1", { expectedUserId: "user-1" }),
+    ).rejects.toBeInstanceOf(ConversationOwnershipMismatchError);
+
+    expect(conversations.delete).not.toHaveBeenCalled();
+  });
+
+  it("treats an explicitly empty expected owner as unauthorized", async () => {
+    const { client, conversations } = createVoltOpsClient();
+    conversations.get.mockResolvedValue(createConversation(""));
+
+    const adapter = new ManagedMemoryAdapter({ databaseId: "db-1", voltOpsClient: client });
+
+    await expect(
+      adapter.updateConversation("conv-1", { title: "Updated" }, { expectedUserId: "" }),
+    ).rejects.toBeInstanceOf(ConversationOwnershipMismatchError);
+
+    expect(conversations.update).not.toHaveBeenCalled();
+  });
+});
diff --git a/packages/voltagent-memory/src/index.ts b/packages/voltagent-memory/src/index.ts
index 75981d47b..7c9bf8dc4 100644
--- a/packages/voltagent-memory/src/index.ts
+++ b/packages/voltagent-memory/src/index.ts
@@ -1,6 +1,9 @@
 import {
   AgentRegistry,
   type Conversation,
+  type ConversationMutationOptions,
+  ConversationNotFoundError,
+  ConversationOwnershipMismatchError,
   type ConversationQueryOptions,
   type ConversationStepRecord,
   type CreateConversationInput,
@@ -165,6 +168,28 @@ export class ManagedMemoryAdapter implements StorageAdapter {
     return handler({ client: this.voltOpsClient, database: this.database });
   }
 
+  private async assertExpectedConversationOwner(
+    id: string,
+    options?: ConversationMutationOptions,
+  ): Promise<void> {
+    if (options?.expectedUserId === undefined) {
+      return;
+    }
+
+    if (options.expectedUserId === "") {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+
+    const conversation = await this.getConversation(id);
+    if (!conversation) {
+      throw new ConversationNotFoundError(id);
+    }
+
+    if (conversation.userId !== options.expectedUserId) {
+      throw new ConversationOwnershipMismatchError(id);
+    }
+  }
+
   private log(message: string, context?: string): void {
     if (this.debug) {
       console.log("[ManagedMemoryAdapter]", message, context ?? "");
@@ -351,23 +376,37 @@ export class ManagedMemoryAdapter implements StorageAdapter {
     });
   }
 
-  updateConversation(
+  async updateConversation(
     id: string,
     updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>,
+    options?: ConversationMutationOptions,
   ): Promise<Conversation> {
+    await this.assertExpectedConversationOwner(id, options);
+
     return this.withClientContext(({ client, database }) => {
       this.log("Updating managed memory conversation", safeStringify({ id, updates }));
       return client.managedMemory.conversations.update(database.id, {
         conversationId: id,
         updates,
+        ...(options?.expectedUserId !== undefined
+          ? { expectedUserId: options.expectedUserId }
+          : {}),
       });
     });
   }
 
-  deleteConversation(id: string): Promise<void> {
+  async deleteConversation(id: string, options?: ConversationMutationOptions): Promise<void> {
+    await this.assertExpectedConversationOwner(id, options);
+
     return this.withClientContext(async ({ client, database }) => {
       this.log("Deleting managed memory conversation", safeStringify({ id }));
-      await client.managedMemory.conversations.delete(database.id, id);
+      await client.managedMemory.conversations.delete(
+        database.id,
+        id,
+        options?.expectedUserId !== undefined
+          ? { expectedUserId: options.expectedUserId }
+          : undefined,
+      );
     }).then(() => undefined);
   }
 
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f8865a8b7..a14708b57 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4374,7 +4374,7 @@ importers:
         specifier: ^1.12.1
         version: 1.17.2
       '@voltagent/core':
-        specifier: ^2.8.1
+        specifier: ^2.9.1
         version: link:../core
       '@voltagent/internal':
         specifier: ^1.0.2
