Skip to content

Scope nested artifact GET/DELETE to the path conversation - #332

Merged
tylerreckart merged 5 commits into
mainfrom
fix/nested-artifact-cid-scope
Sep 21, 2026
Merged

tylerreckart merged 5 commits into
mainfrom
fix/nested-artifact-cid-scope

Conversation

@cursor

@cursor cursor Bot commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

Problem

GET/DELETE /v1/conversations/:cid/artifacts/:aid (and /raw) looked up by (tenant_id, artifact_id) only. :cid was parsed and unused. Same-tenant callers could read or delete another conversation's blob (or a TUI-origin thread's blob) by guessing the numeric id. List and create on the same prefix already require an HTTP-visible conversation; the documented contract for the item routes is 404 unless the id exists for that tenant+conversation pair. Agent /read already enforced conversation scope.

Tenant-wide /v1/artifacts/:aid is intentionally tenant-scoped and is unchanged.

Fix

get_artifact_meta, get_artifact_content, and delete_artifact take an optional conversation_id. When it is > 0, the SQL (and delete's pre-check) require that conversation so a mismatched :cid cannot nullify memory links or drop a sibling row. Nested HTTP handlers pass :cid and 404 missing/TUI conversations like list/create.

Tests

unit_artifacts — matching conversation_id still reads/deletes; sibling conversation_id is a miss; mismatched delete is a no-op (row and memory artifact_id stay); tenant-wide (conversation_id == 0) still works.

Independently mergeable against main. Code hunks auto-merge with #321–#331 (tenant_store artifact methods / nested artifact router are far from A2A, EntryFilter, and conversation list). CHANGELOG [Unreleased] will need a rebase after whichever sibling merges first.

Open in Web View Automation 

Note

Medium Risk
Closes cross-conversation artifact read/delete within a tenant (authorization-scoped data); behavior change for clients that relied on mismatched :cid, but matches documented API.

Overview
Fixes a tenant-internal isolation gap: nested GET/DELETE /v1/conversations/:cid/artifacts/:aid (and /raw) previously ignored :cid and keyed only on (tenant_id, artifact_id), so callers could read or delete another thread’s blob by id. List/create on the same prefix already required an HTTP-visible conversation; this change aligns item routes with that contract.

Store + HTTP: get_artifact_meta, get_artifact_content, and delete_artifact take an optional conversation_id; when it is > 0, SQL (and delete’s pre-check) require the row to belong to that conversation. Mismatched delete is a no-op so memory artifact_id links on sibling rows are not cleared. Nested handlers pass :cid, return 404 with "conversation not found" for missing or TUI-origin conversations, and "artifact not found" when the id is wrong for that pair. Tenant-wide /v1/artifacts/:aid stays unchanged (conversation_id == 0).

Docs failure-mode tables and CHANGELOG [Unreleased] note the split 404s; unit_artifacts adds coverage for scoped read/delete vs tenant-wide behavior.

Reviewed by Cursor Bugbot for commit 09d8d63. Bugbot is set up for automated code reviews on this repo. Configure here.

GET/DELETE /v1/conversations/:cid/artifacts/:aid (and /raw) looked up
by tenant+id only, so a sibling-thread or TUI-origin id succeeded.
Lookups and delete now take an optional conversation_id; nested routes
also 404 missing/TUI conversations like list/create. Tenant-wide
/v1/artifacts/:aid is unchanged.

Co-authored-by: Tyler Reckart <tylerreckart@users.noreply.github.com>
@tylerreckart
tylerreckart enabled auto-merge (squash) September 21, 2026 13:23
Keep both Unreleased changelog entries.

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_e2886bd4-48a5-4832-9d57-74b089a2b443)

Keep both Unreleased changelog entries.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep both Unreleased changelog entries.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tylerreckart
tylerreckart merged commit 3273549 into main Sep 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.

3 participants