Skip to content

Disable AI memory for public URLs and embeds without external_user_id - #10043

Closed
nishantmonu51 wants to merge 2 commits into
mainfrom
nishant/disable-ai-memory-for-embeds
Closed

nishantmonu51 wants to merge 2 commits into
mainfrom
nishant/disable-ai-memory-for-embeds

Conversation

@nishantmonu51

@nishantmonu51 nishantmonu51 commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

AI chat memory (#9992) is keyed on the runtime JWT subject, but ai.MemoryAvailable only treated an empty subject as anonymous. Three token types put a shared ID in the subject, so every viewer read and wrote the same memory store:

  • Embeds issued without external_user_id (the documented default): the subject is the service or user ID of the token that called GetIFrame, shared by every viewer of the embed.
  • Public URLs: the subject is the magic token ID, shared by everyone with the link.
  • Service tokens used directly (GetProject, GetDeploymentCredentials without external_user_id): the subject is the service ID, shared by every caller.

Changes:

  • admin/server/runtime_jwt.go: magic-token JWTs carry public_url: true, service-owner JWTs carry service: true, and tokens issued with an external_user_id carry external_user: true. The markers are derived at issuance and stripped from stored or caller-supplied attributes, so attributes: {external_user: true} cannot turn memory on for a shared subject.
  • runtime/feature_flags.go: ResolveFeatureFlags forces chat_memory to false when public_url || ((embed || service) && !external_user), whatever the project configures. The runtime enforces it via ai.MemoryAvailable (RPCs and the update_memory tool) and the UI hides the memory controls when the flag is off.
  • Embeds and service tokens with external_user_id keep memory: their subject is per viewer.
  • MemoryUpdateChip.svelte is hidden when memory is off, so an older conversation never links to a memory manager the runtime refuses to serve.
  • Docs updated for embeds, service tokens, public URLs and the chat_memory flag.

Tests: feature flag resolution per principal type, ai.MemoryAvailable gates, memory RPCs for service, embed, public URL and external user claims, and the admin JWT test asserts the markers for service tokens, GetIFrame with and without external_user_id, spoofed custom attributes, and magic tokens.

Not covered: "View as" (an admin viewing as another user reads that user's memories) is unchanged.

Affects 0.91 only (memory shipped after the 0.90 cut). Intended for cherry-pick into release-0.91.

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

AI memory (#9992) is keyed on the runtime JWT subject and only treated an
empty subject as anonymous. But the subject is shared by several viewers
in two cases: an embed issued without external_user_id puts the issuer's
identity (a service or user ID) on every viewer's token, and a public
URL puts the magic token ID on everyone with the link. Viewers of the
same embed or public URL therefore shared one memory store, so one
viewer's "remember that..." silently shaped the answers of the others,
and Manage memory let any viewer list, edit or delete the rest.

Memory now needs a subject that identifies one viewer:
- The admin server marks magic auth token JWTs with the attribute
  public_url, since they carry the creator's attributes and were
  otherwise indistinguishable from the creator's own token, and marks
  tokens issued with an external_user_id with external_user. Embed
  tokens already carry embed: true.
- ResolveFeatureFlags resolves chat_memory to false for public URLs and
  for embeds without external_user, whatever the project configures.
  MemoryAvailable (the memory RPCs and the update_memory tool) enforces
  that flag, and GetInstance returns it to the UI, which already hides
  the memory button and Settings > AI memory, and now the "Memory
  updated" notice, when it is off.
- Docs state that memory is per user, available in embeds only with
  external_user_id, and never through public URLs.

Tests cover service-token, external-user and public URL claims in the
runtime, and the JWT attributes issued for service-token embeds with and
without an external user ID and for a public URL in the admin server.
…er-side

A service token used directly (GetProject, GetDeploymentCredentials) has the service ID as subject, shared by every caller, so it now carries service: true and memory is off unless an external_user_id is set.
The service, public_url and external_user markers are stripped from stored and caller-supplied attributes before being set, so attributes: {external_user: true} cannot turn memory on for a shared subject.
@k-anshul

Copy link
Copy Markdown
Member

closed in favour of #10046

@k-anshul k-anshul closed this Oct 21, 2026
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.

2 participants