[security] Mass assignment fix sweep
fix: [security] Mass assignment fix sweep
[security] Mass assignment fix sweepc80a35-fix-security-mass-assignment-fix-sweep-cve-2026-56422fixsecurity mass assignment fix sweep
Committed by iglocska
commit message
fix: [security] Mass assignment fix sweep
TagCollectionsController::addWithTags() — id-redirection in a create-only action.
addWithTags() builds the save array straight from request->data, forces
org_id/user_id to the current user, then calls TagCollection->saveAssociated()
without ever stripping the primary key. CakePHP treats an id present in the save
data as an UPDATE target, so a supplied TagCollection[id] turned the insert into
a covert UPDATE of an arbitrary tag collection — and because org_id/user_id are
force-pinned to the attacker, that row was simultaneously re-owned to them
(overwrite + steal). Reachable by a non-site-admin perm_tag_editor user (ACL:
perm_tag_editor + theming_enabled), so the lesser-user model applies; REST-
reachable, so CSRF field-hashing does not help.
Fix: unset($data['TagCollection']['id']) before saveAssociated so the action
always inserts a new row, mirroring TagCollection::import() (which already strips
id + forces ownership) and the edit/editWithTags paths (which pin id to the
authorised record).
Live before/after proven: org-531 perm_tag_editor user POSTed
{"TagCollection":{"id":1,...}} to addWithTags — pre-fix org-1's collection 1 was
overwritten and re-owned to org-531; post-fix collection 1 is untouched and a new
row is inserted instead. Legitimate creation still works.
Other actions audited SAFE: add (CRUD->add strips id + beforeSave forces
ownership), import (model strips id + forces ownership, dedups by uuid), edit /
editWithTags (pin id/uuid/org_id/user_id to the stored authorised record, prior
commit 9341690e9 + M0), delete (ACL + CRUD delete on route id), addTag (perm_tagger
+ canModifyTagCollection, fresh join rows scoped to the authorised collection),
removeTag (deletes only a TagCollectionTag contained in the loaded authorised
collection — no body-id redirect). deleteSelection's checkModifyCallback returns
perm_site_admin (a safe gate: no lesser user passes), unlike the global-flag
deleteSelection findings parked for the post-sweep cleanup. tag_collections has no
distribution/sharing_group_id, so no sharing-group parity gap.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>Editor assessment
This commit patches CVE-2026-56422. The body explains id redirection in TagCollectionsController::addWithTags(), where the action built the save array from request data, force-pinned ownership to the caller, and never stripped the primary key, producing an overwrite plus steal. That is a strong, specific account, and unsetting the id before saveAssociated mirrors the existing import path. The weakness is size: the entry continues with a multi-item audit of every other action, runs to well over two thousand characters, and mixes in unrelated findings about deleteSelection, burying the actual fix. The blanket sweep subject compounds the problem.