fix(security): list items need write access to their list (FLAW-27)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 59s

Creating, checking, editing, deleting, reordering and clearing list
items did not check the list at all: any logged-in user with a list or
item ID could change it, viewers of shared lists as well. All item
endpoints and converting a thought into a list item now require owner
or editor rights and that the item belongs to the list (404 without
access, 403 for viewers).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 14:28:39 +01:00
1 parent 11c14fa9ff
commit 3900c6104e
5 files changed
+125

No files matched your search

+35
View File
@@ -169,3 +169,38 @@ func TestDataSurvivesRestart(t *testing.T) {
t.Fatalf("user_version = %d, want %d", v, schemaVersion)
}
}
func TestListItemsNeedWriteAccess(t *testing.T) {
store, err := NewStore(filepath.Join(t.TempDir(), "listacl.db"))
if err != nil {
t.Fatal(err)
}
defer store.Close()
openSharing(t, store)
anna, _ := store.CreateUser("anna@example.com", "hash", "Anna", "member")
ben, _ := store.CreateUser("ben@example.com", "hash", "Ben", "member")
eve, _ := store.CreateUser("eve@example.com", "hash", "Eve", "member")
list, _ := store.CreateList(anna.ID, "Einkauf", "", "shopping")
item, _ := store.CreateListItem(list.ID, "Milch", "", "", 0, anna.ID)
other, _ := store.CreateList(eve.ID, "Eves Liste", "", "shopping")
otherItem, _ := store.CreateListItem(other.ID, "Geheim", "", "", 0, eve.ID)
_, _ = store.AddListShare(anna.ID, list.ID, "user", ben.ID, "viewer")
if err := store.EnsureListItemsWritable(anna.ID, list.ID, item.ID); err != nil {
t.Errorf("owner must write: %v", err)
}
if err := store.EnsureListItemsWritable(ben.ID, list.ID, item.ID); err != ErrListReadOnly {
t.Errorf("viewer must be read-only, got %v", err)
}
if err := store.EnsureListItemsWritable(eve.ID, list.ID, ""); err != ErrListNotFound {
t.Errorf("stranger must not see the list, got %v", err)
}
if err := store.EnsureListItemsWritable(anna.ID, list.ID, otherItem.ID); err != ErrListNotFound {
t.Errorf("an item of another list must not be reachable through my list, got %v", err)
}
// Turning a thought into an item of someone else's list is refused as well
th, _ := store.CreateThoughtWithDetails(eve.ID, "Spam", "normal", "manual", "", "", "todo", "")
if _, err := store.UpdateThoughtTriage(eve.ID, th.ID, "keep", "list_item", list.ID, "", ""); err == nil {
t.Errorf("thought must not become an item of a list without write access")
}
}