CVE-2026-53911
Description
An authenticated mass-assignment flaw in Cerebrate before 1.37 lets attackers supply an id via request input, causing CRUD edit operations to update arbitrary records of the same entity type.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
An authenticated mass-assignment flaw in Cerebrate before 1.37 lets attackers supply an `id` via request input, causing CRUD edit operations to update arbitrary records of the same entity type.
Vulnerability
Cerebrate before version 1.37 allowed the id primary key field to be supplied through request input during CRUD edit operations and custom entity patching flows. In entities that did not explicitly mark id as inaccessible — including User, Role, UserSetting, LocalTool, PermissionLimitation, and EnumerationCollection — an attacker could submit a crafted edit request containing the id of another record, causing the save operation to update that unrelated record instead of the one identified by the route parameter [1].
Exploitation
An authenticated attacker with access to any endpoint that performs a CRUD edit on an affected entity type can exploit this by sending a crafted HTTP request (e.g., via a form body or JSON payload) that includes an id field pointing to a different record. No special privileges beyond basic authentication are required; for instance, the UserSettings edit functionality is reachable by any authenticated user. The attacker must know or guess the target record’s id, and the attack is performed when the server processes the malicious input without stripping the primary key [1].
Impact
On success, the attacker overwrites a record of the same entity type that they would not normally be authorized to edit. The specific impact depends on the endpoint and writable fields: using the User entity example, an attacker could modify another user’s settings, role, or other attributes, leading to privilege escalation or unauthorized modification of sensitive data. The scope is limited to the entity type of the exploited endpoint, and no arbitrary file access or remote code execution is implied by the available references [1].
Mitigation
Cerebrate version 1.37 fixes the vulnerability by stripping id from request input after beforeMarshal callbacks in both the add() and edit() methods, and by globally marking id as inaccessible in the base AppModel entity [1]. Users must upgrade to Cerebrate 1.37 or later. No workaround is available for unpatched versions. This issue is not listed on CISA’s Known Exploited Vulnerabilities (KEV) catalog as of the publication date.
AI Insight generated on Jun 11, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2(expand)+ 1 more
- (no CPE)
- (no CPE)range: <1.37
Patches
1b3c8f951b063fix: [security] prevent id mass-assignment in CRUD edit() and globally via AppModel
3 files changed · +28 −3
src/Controller/Component/CRUDComponent.php+12 −3 modified@@ -448,9 +448,6 @@ public function add(array $params = []): void 'accessibleFields' => $data->getAccessibleFieldForNew(), ]; $input = $this->__massageInput($params); - if (!empty($input['id'])) { - unset($input['id']); - } if (!empty($params['fields'])) { $patchEntityParams['fields'] = $params['fields']; } @@ -460,6 +457,12 @@ public function add(array $params = []): void throw new NotFoundException(__('Could not save {0} due to the marshaling failing. Your input is bad and you should feel bad.', $this->ObjectAlias)); } } + // Strip the primary key from user input AFTER beforeMarshal, so that neither the + // request body nor a beforeMarshal callback can mass-assign `id` and cause save() + // to overwrite an unrelated record. Mirrors edit(). + if (!empty($input['id'])) { + unset($input['id']); + } if ($metaFieldsEnabled) { $massagedData = $this->massageMetaFields($data, $input, $metaTemplates); unset($input['MetaTemplates']); // Avoid MetaTemplates to be overriden when patching entity @@ -814,6 +817,12 @@ public function edit(int $id, array $params = []): void throw new NotFoundException(__('Could not save {0} due to the marshaling failing. Your input is bad and you should feel bad.', $this->ObjectAlias)); } } + // Strip the primary key from user input AFTER beforeMarshal. The entity is always + // loaded by the URL `$id`; allowing `id` from the body would let an attacker + // redirect the UPDATE to a different record (mass-assignment). Mirrors add(). + if (!empty($input['id'])) { + unset($input['id']); + } $cleanupMetaFields = []; if ($metaFieldsEnabled) { $massagedData = $this->massageMetaFields($data, $input, $metaTemplates, $cleanupMetaFields);
src/Controller/MetaTemplatesController.php+1 −0 modified@@ -179,6 +179,7 @@ public function migrateOldMetaTemplateToNewestVersionForEntity($template_id, $en $metaFieldsToDelete[] = $entity->meta_fields[$i]; } } + unset($inputData['id']); // never let the request body reassign the entity PK (mass-assignment guard) $data = $entityTable->patchEntity($data, $inputData); $savedData = $entityTable->save($data); if ($savedData !== false) {
src/Model/Entity/AppModel.php+15 −0 modified@@ -24,6 +24,21 @@ class AppModel extends Entity ACTION_LOGIN_FAIL = 'login_fail', ACTION_LOGOUT = 'logout'; + /** + * Global mass-assignment guard inherited by every entity that does not declare its + * own $_accessible. `'*' => true` preserves the historical default (all columns are + * marshallable); `'id' => false` ensures the primary key can NEVER be set from request + * input via patchEntity()/newEntity(), preventing id mass-assignment (i.e. redirecting + * a save() onto an unrelated record). Entities that define their own $_accessible + * already set `'id' => false` explicitly. Code that must set a PK does so via direct + * assignment ($entity->id = ...), which bypasses accessibility and is unaffected. + * + * @var array<string, bool> + */ + protected $_accessible = [ + '*' => true, + 'id' => false, + ]; public function getConstant($name) {
Vulnerability mechanics
Root cause
"Missing mass-assignment guard on the `id` primary key field allows an attacker-supplied `id` value in the request body to redirect `save()` to an unrelated record."
Attack vector
An authenticated attacker submits a crafted HTTP request to a CRUD `edit()` endpoint (or certain custom patching flows) that includes an `"id": <other_record_id>` parameter in the request body. Because the entity's `$_accessible` definition did not mark `id` as inaccessible, the `patchEntity()` call marshals the attacker-supplied `id`, causing `save()` to overwrite an unrelated record instead of the one identified by the route parameter. The `UserSettings::edit` endpoint is reachable by any authenticated user, making it a low-barrier entry point. The impact depends on which entity type is targeted and which fields are writable, but can include unauthorized modification of User, Role, UserSetting, LocalTool, PermissionLimitation, or EnumerationCollection records. [CWE-915]
Affected code
The vulnerability resides in `CRUDComponent::edit()` and `CRUDComponent::add()` in `src/Controller/Component/CRUDComponent.php`, as well as `MetaTemplatesController::migrateOldMetaTemplateToNewestVersionForEntity()` in `src/Controller/MetaTemplatesController.php`. The root cause is that the `id` primary key field was not stripped from user request input before marshalling, allowing mass-assignment to redirect `save()` to an unrelated record. The fix also adds a global `$_accessible = ['*' => true, 'id' => false]` guard in `AppModel` (`src/Model/Entity/AppModel.php`) to harden all entities that lack their own `_accessible` definition. [patch_id=5590530]
What the fix does
The patch moves the `unset($input['id'])` call to **after** the `beforeMarshal` callback in both `add()` and `edit()`, ensuring that neither the raw request body nor any callback can reintroduce the primary key into the marshalled data. It also adds `unset($inputData['id'])` in `MetaTemplatesController::migrateOldMetaTemplateToNewestVersionForEntity()` for the same reason. Finally, `AppModel` now declares `$_accessible = ['*' => true, 'id' => false]`, making the `id` field globally inaccessible to mass-assignment for any entity that does not define its own `$_accessible`. Direct assignment (`$entity->id = ...`) remains unaffected, so internal code that must set a PK continues to work. [patch_id=5590530]
Preconditions
- authThe attacker must be an authenticated user of the Cerebrate application.
- inputThe attacker must send a request to a CRUD edit() endpoint or a custom patching flow (e.g., MetaTemplatesController::migrateOldMetaTemplateToNewestVersionForEntity) that accepts an 'id' field in the request body.
- configThe target entity type must not have explicitly marked 'id' as inaccessible in its $_accessible definition (affected: User, Role, UserSetting, LocalTool, PermissionLimitation, EnumerationCollection).
Generated on Jun 11, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
1News mentions
0No linked articles in our index yet.