Summary. PATCH /api/artists/{id} authorizes shared-canonical metadata edits off the flat account_artist_ids roster edge, so any account that merely rosters an artist can overwrite that canonical's shared name / image / instruction — shared-state vandalism across every other account that rosters the same artist.
Split out of chat#1860 as an independent, lower-severity item (it is about shared-metadata writes, not connector act-as authority — chat#1860's acute connector vector is already remediated). Related redesign tracker: chat#1865.
Trigger / root cause. lib/artists/validateUpdateArtistRequest.ts:88 gates the update with checkAccountArtistAccess(requesterAccountId, artistId), which returns true on a bare account_artist_ids row (lib/artists/checkAccountArtistAccess.ts). Since artists are canonical and shared, that lets any roster holder mutate fields other accounts see.
Expected vs actual.
- Expected: editing a shared canonical's
name / image / instruction requires more than a bare roster row.
- Actual: any account with the artist in its roster can PATCH those fields, and the change is visible to every other account rostering that canonical.
Fix (proposed). Gate PATCH /api/artists/{id} metadata writes on something stronger than the flat roster edge — align with the connector-authority model (self / owning org / RECOUP_ORG admin), or restrict shared-canonical field edits to a privileged relationship. Decide the exact bar during implementation; keep read/analytics and roster association unaffected.
Done when. An account that only rosters canonical A cannot change A's shared name / image / instruction (receives 403); an authorized relationship still can; verified live against the preview with two accounts. Roster/read paths unchanged.
Notes. Lower severity than the connector work and independent of the re-key — can be picked up any time. Mirrors the P0b pattern of swapping checkAccountArtistAccess for a stricter check at a single call site.
Summary.
PATCH /api/artists/{id}authorizes shared-canonical metadata edits off the flataccount_artist_idsroster edge, so any account that merely rosters an artist can overwrite that canonical's sharedname/image/instruction— shared-state vandalism across every other account that rosters the same artist.Split out of chat#1860 as an independent, lower-severity item (it is about shared-metadata writes, not connector act-as authority — chat#1860's acute connector vector is already remediated). Related redesign tracker: chat#1865.
Trigger / root cause.
lib/artists/validateUpdateArtistRequest.ts:88gates the update withcheckAccountArtistAccess(requesterAccountId, artistId), which returns true on a bareaccount_artist_idsrow (lib/artists/checkAccountArtistAccess.ts). Since artists are canonical and shared, that lets any roster holder mutate fields other accounts see.Expected vs actual.
name/image/instructionrequires more than a bare roster row.Fix (proposed). Gate
PATCH /api/artists/{id}metadata writes on something stronger than the flat roster edge — align with the connector-authority model (self / owning org / RECOUP_ORG admin), or restrict shared-canonical field edits to a privileged relationship. Decide the exact bar during implementation; keep read/analytics and roster association unaffected.Done when. An account that only rosters canonical A cannot change A's shared
name/image/instruction(receives 403); an authorized relationship still can; verified live against the preview with two accounts. Roster/read paths unchanged.Notes. Lower severity than the connector work and independent of the re-key — can be picked up any time. Mirrors the P0b pattern of swapping
checkAccountArtistAccessfor a stricter check at a single call site.