Skip to content

fix(tools): reject out-of-scope containerTag in documentDelete - #1758

Open
Atharvsinh-codez wants to merge 1 commit into
supermemoryai:mainfrom
Atharvsinh-codez:fix/tools-document-delete-scope
Open

Atharvsinh-codez wants to merge 1 commit into
supermemoryai:mainfrom
Atharvsinh-codez:fix/tools-document-delete-scope

Conversation

@Atharvsinh-codez

Copy link
Copy Markdown

What was wrong

documentDelete accepts an optional containerTag from the model and uses it as the scope for the delete. The other tools that take a containerTag (getProfile, documentList, memoryForget) only allow tags the developer configured. documentDelete never checked, so a model (or a prompt-injected input) could pass any tag and delete documents scoped to it.

deleteDocumentByIdentifier still refuses documents whose tags fall outside the scope it is given. But the scope itself came straight from the model, so that check wasn't protecting anything.

It happens in both tool surfaces:

  • documentDeleteTool in packages/tools/src/ai-sdk.ts (also re-exported by packages/ai-sdk)
  • createDocumentDeleteFunction in packages/tools/src/openai/tools.ts

Repro

With containerTags: ["tenant-a"] configured and a document that only lives in tenant-b:

documentDeleteTool(apiKey, { containerTags: ["tenant-a"] })
  .execute({ documentId: "doc_in_tenant_b", containerTag: "tenant-b" })

On main this calls documents.deleteBulk and succeeds. With this change it returns success: false with Container tag "tenant-b" is outside the configured scope. and makes no SDK calls.

The fix

Both tools now check the supplied tag against the configured container tags before doing anything else, and return the same "outside the configured scope" error the other tools use. If no tag is passed, behavior is unchanged (the configured union is used). Passing another tag that is configured still works.

Relation to #1504 / #1755

This is the same class of bug as #1504, which #1755 bundles. As far as I can tell, that work covers getProfile, documentList and memoryForget but not documentDelete, and its scope test doesn't include it either. I used a small inline check so this applies cleanly on main without depending on #1755. Once #1755 lands, it can be switched to resolveConfiguredContainerTag in a one-line change. Happy to rebase if you'd rather have it that way.

Tests

New file packages/tools/src/document-delete-scope.test.ts (mocked SDK, no network):

  • ai-sdk and OpenAI variants reject a tag outside the configured scope, with no get/list/deleteBulk calls
  • a projectId config rejects an outside tag
  • selecting another explicitly configured tag still works
  • no tag falls back to the configured union
bunx vitest run src/document-delete-scope.test.ts src/tool-operations.test.ts
  23 passed

biome check is clean on the changed files. tsc --noEmit reports the same errors as main (none new). src/tools.test.ts needs a real SUPERMEMORY_API_KEY, so I didn't run it.

documentDelete takes an optional containerTag from the model and uses it
as the scope for the delete. getProfile, documentList and memoryForget
only accept tags the developer configured, but documentDelete never
checked, so the model could name any tag and delete documents in it.

This is the same gap in both tool surfaces (ai-sdk documentDeleteTool and
the OpenAI createDocumentDeleteFunction). Both now reject a tag that is
not in the configured container tags before making any request, with the
same "outside the configured scope" error the other tools use.

Added tests for both surfaces, the implicit projectId scope, selecting
another configured tag, and the default no-tag path.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant