CVE-2026-47233
Admidio: Any logged-in user can delete inventory fields via `mode=field_delete` — incomplete fix of #2024
Admidio is an open-source user management solution. Version 5.0.9 added a missing isAdministratorInventory() gate to case 'item_delete': in modules/inventory.php. The same fix was not applied to the sibling case 'field_delete': handler, which destroys an entire inventory field definition, cascading to every adm_inventory_item_data row that referenced that field and every adm_inventory_field_options entry. The handler validates only a session-bound CSRF token; there is no isAdministratorInventory() check at the controller level, and Admidio\Inventory\Entity\ItemField::delete() does not enforce one at the entity level either (unlike its sibling ItemField::save(), which does check $gCurrentUser->isAdministrator()). Any user who can log in to the site can permanently destroy a non-system inventory field by sending one POST. Version 5.0.10 provides an updated fix.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.5
Admidio: Any logged-in user can delete inventory fields via `mode=field_delete` — incomplete fix of #2024
Admidio is an open-source user management solution. Version 5.0.9 added a missing isAdministratorInventory() gate to case 'item_delete': in modules/inventory.php. The same fix was not applied to the sibling case 'field_delete': handler, which destroys an entire inventory field definition, cascading to every adm_inventory_item_data row that referenced that field and every adm_inventory_field_options entry. The handler validates only a session-bound CSRF token; there is no isAdministratorInventory() check at the controller level, and Admidio\Inventory\Entity\ItemField::delete() does not enforce one at the entity level either (unlike its sibling ItemField::save(), which does check $gCurrentUser->isAdministrator()). Any user who can log in to the site can permanently destroy a non-system inventory field by sending one POST. Version 5.0.10 provides an updated fix.
- Record
CVE-2026-47233- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N - Weakness
- CWE-862, CWE-1281
- Updated
- 2026-11-02
EUVDEUVD-2026-57214
6.5
Admidio is an open-source user management solution. Version 5.0.9 added a missing isAdministratorInventory() gate to case 'item_delete': in modules/inventory.php. The same fix was not applied to the sibling case 'field_delete': handler, which destroys an entire inventory field definition, cascading to every adm_inventory_item_data row that referenced that field and every adm_inventory_field_options entry. The handler validates only a session-bound CSRF token; there is no isAdministratorInventory() check at the controller level, and Admidio\Inventory\Entity\ItemField::delete() does not enforce one at the entity level either (unlike its sibling ItemField::save(), which does check $gCurrentUser->isAdministrator()). Any user who can log in to the site can permanently destroy a non-system inventory field by sending one POST. Version 5.0.10 provides an updated fix.
- Record
EUVD-2026-57214- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-xw54-c3mx-9pm3
6.5
Admidio: Any logged-in user can delete inventory fields via `mode=field_delete` — incomplete fix of #2024
Summary
Commit d37ca6b27b9674238e58491cf7ba292e66898f15 ("Delete item not check admin rights #2024", 2026-04-12) added a missing isAdministratorInventory() gate to case 'item_delete': in modules/inventory.php. The same fix was not applied to the sibling case 'field_delete': handler, which destroys an entire inventory field definition, cascading to every adm_inventory_item_data row that referenced that field and every adm_inventory_field_options entry. The handler validates only a session-bound CSRF token; there is no isAdministratorInventory() check at the controller level, and Admidio\Inventory\Entity\ItemField::delete() does not enforce one at the entity level either (unlike its sibling ItemField::save(), which does check $gCurrentUser->isAdministrator()). Any user who can log in to the site can permanently destroy a non-system inventory field by sending one POST.
Details
Vulnerable Code
modules/inventory.php mode dispatch at the top of the file:
// modules/inventory.php:64-72 (top-level rights gate)
if ($gSettingsManager->getInt('inventory_module_enabled') === 0) {
throw new Exception('SYS_MODULE_DISABLED');
} elseif ($gSettingsManager->getInt('inventory_module_enabled') === 2 && !$gValidLogin
|| ($gSettingsManager->getInt('inventory_module_enabled') === 3 && !$gCurrentUser->isAdministratorInventory())
|| ($gSettingsManager->getInt('inventory_module_enabled') === 4 && !InventoryPresenter::isCurrentUserKeeper() && !$gCurrentUser->isAdministratorInventory())
|| ($gSettingsManager->getInt('inventory_module_enabled') === 5 && !$gCurrentUser->isAllowedToSeeInventory() && !$gCurrentUser->isAdministratorInventory())) {
throw new Exception('SYS_NO_RIGHTS');
}
inventory_module_enabled=2 is the default value (install/db_scripts/preferences.php: 'inventory_module_enabled' => '2',). At this setting the only gate is $gValidLogin — any logged-in user reaches the switch.
modules/inventory.php:123-131 — field_delete only checks the session CSRF, not admin rights:
case 'field_delete':
// check the CSRF token of the form against the session token
SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']);
$itemFieldService = new ItemFieldService($gDb, $getinfUUID);
$itemFieldService->delete();
echo json_encode(array('status' => 'success', 'message' => $gL10n->get('SYS_INVENTORY_ITEMFIELD_DELETED')));
break;
SecurityUtils::validateCsrfToken (src/Infrastructure/Utils/SecurityUtils.php) is a session-token compare:
public static function validateCsrfToken(string $csrfToken)
{
global $gCurrentSession;
if ($csrfToken !== $gCurrentSession->getCsrfToken()) {
throw new Exception('Invalid or missing CSRF token!');
}
}
The token is the session's CSRF token, which the actor's own session prints on every page (it appears in ?mode=field_list's response in the data-csrf JSON callback). So a non-admin attacker has it for free.
src/Inventory/Service/ItemFieldService.php:46-49 — the service just delegates:
public function delete(): bool
{
return $this->itemFieldRessource->delete();
}
src/Inventory/Entity/ItemField.php:54-88 — the entity's delete() blocks system fields via inf_system==1 but otherwise has no isAdministrator() check:
public function delete(): bool
{
global $gCurrentOrgId;
if ($this->getValue('inf_system') == 1) {
// System fields could not be deleted
throw new Exception('Item fields with the flag "system" could not be deleted.');
}
$this->db->startTransaction();
// close gap in sequence
$sql = 'UPDATE ' . TBL_INVENTORY_FIELDS . ' SET inf_sequence = inf_sequence - 1 ...';
$this->db->queryPrepared($sql, ...);
// delete all data of this field in the item data table
$sql = 'DELETE FROM ' . TBL_INVENTORY_ITEM_DATA . ' WHERE ind_inf_id = ? -- $infId';
$this->db->queryPrepared($sql,…
- Record
GHSA-xw54-c3mx-9pm3- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N - Weakness
- CWE-862, CWE-1281
- Updated
- 2026-11-02
NVD
6.5
Admidio is an open-source user management solution. Version 5.0.9 added a missing isAdministratorInventory() gate to case 'item_delete': in modules/inventory.php. The same fix was not applied to the sibling case 'field_delete': handler, which destroys an entire inventory field definition, cascading to every adm_inventory_item_data row that referenced that field and every adm_inventory_field_options entry. The handler validates only a session-bound CSRF token; there is no isAdministratorInventory() check at the controller level, and Admidio\Inventory\Entity\ItemField::delete() does not enforce one at the entity level either (unlike its sibling ItemField::save(), which does check $gCurrentUser->isAdministrator()). Any user who can log in to the site can permanently destroy a non-system inventory field by sending one POST. Version 5.0.10 provides an updated fix.
- Record
CVE-2026-47233- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N - Weakness
- CWE-862, CWE-1281
- Updated
- 2026-11-02
OSV
6.5
Admidio: Any logged-in user can delete inventory fields via `mode=field_delete` — incomplete fix of #2024
Admidio is an open-source user management solution. Version 5.0.9 added a missing isAdministratorInventory() gate to case 'item_delete': in modules/inventory.php. The same fix was not applied to the sibling case 'field_delete': handler, which destroys an entire inventory field definition, cascading to every adm_inventory_item_data row that referenced that field and every adm_inventory_field_options entry. The handler validates only a session-bound CSRF token; there is no isAdministratorInventory() check at the controller level, and Admidio\Inventory\Entity\ItemField::delete() does not enforce one at the entity level either (unlike its sibling ItemField::save(), which does check $gCurrentUser->isAdministrator()). Any user who can log in to the site can permanently destroy a non-system inventory field by sending one POST. Version 5.0.10 provides an updated fix.
- Record
CVE-2026-47233- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N - Weakness
- CWE-1281, CWE-862
- Updated
- 2026-11-02
OSVGHSA-xw54-c3mx-9pm3
6.5
Admidio: Any logged-in user can delete inventory fields via `mode=field_delete` — incomplete fix of #2024
Summary
Commit d37ca6b27b9674238e58491cf7ba292e66898f15 ("Delete item not check admin rights #2024", 2026-04-12) added a missing isAdministratorInventory() gate to case 'item_delete': in modules/inventory.php. The same fix was not applied to the sibling case 'field_delete': handler, which destroys an entire inventory field definition, cascading to every adm_inventory_item_data row that referenced that field and every adm_inventory_field_options entry. The handler validates only a session-bound CSRF token; there is no isAdministratorInventory() check at the controller level, and Admidio\Inventory\Entity\ItemField::delete() does not enforce one at the entity level either (unlike its sibling ItemField::save(), which does check $gCurrentUser->isAdministrator()). Any user who can log in to the site can permanently destroy a non-system inventory field by sending one POST.
Details
Vulnerable Code
modules/inventory.php mode dispatch at the top of the file:
// modules/inventory.php:64-72 (top-level rights gate)
if ($gSettingsManager->getInt('inventory_module_enabled') === 0) {
throw new Exception('SYS_MODULE_DISABLED');
} elseif ($gSettingsManager->getInt('inventory_module_enabled') === 2 && !$gValidLogin
|| ($gSettingsManager->getInt('inventory_module_enabled') === 3 && !$gCurrentUser->isAdministratorInventory())
|| ($gSettingsManager->getInt('inventory_module_enabled') === 4 && !InventoryPresenter::isCurrentUserKeeper() && !$gCurrentUser->isAdministratorInventory())
|| ($gSettingsManager->getInt('inventory_module_enabled') === 5 && !$gCurrentUser->isAllowedToSeeInventory() && !$gCurrentUser->isAdministratorInventory())) {
throw new Exception('SYS_NO_RIGHTS');
}
inventory_module_enabled=2 is the default value (install/db_scripts/preferences.php: 'inventory_module_enabled' => '2',). At this setting the only gate is $gValidLogin — any logged-in user reaches the switch.
modules/inventory.php:123-131 — field_delete only checks the session CSRF, not admin rights:
case 'field_delete':
// check the CSRF token of the form against the session token
SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']);
$itemFieldService = new ItemFieldService($gDb, $getinfUUID);
$itemFieldService->delete();
echo json_encode(array('status' => 'success', 'message' => $gL10n->get('SYS_INVENTORY_ITEMFIELD_DELETED')));
break;
SecurityUtils::validateCsrfToken (src/Infrastructure/Utils/SecurityUtils.php) is a session-token compare:
public static function validateCsrfToken(string $csrfToken)
{
global $gCurrentSession;
if ($csrfToken !== $gCurrentSession->getCsrfToken()) {
throw new Exception('Invalid or missing CSRF token!');
}
}
The token is the session's CSRF token, which the actor's own session prints on every page (it appears in ?mode=field_list's response in the data-csrf JSON callback). So a non-admin attacker has it for free.
src/Inventory/Service/ItemFieldService.php:46-49 — the service just delegates:
public function delete(): bool
{
return $this->itemFieldRessource->delete();
}
src/Inventory/Entity/ItemField.php:54-88 — the entity's delete() blocks system fields via inf_system==1 but otherwise has no isAdministrator() check:
public function delete(): bool
{
global $gCurrentOrgId;
if ($this->getValue('inf_system') == 1) {
// System fields could not be deleted
throw new Exception('Item fields with the flag "system" could not be deleted.');
}
$this->db->startTransaction();
// close gap in sequence
$sql = 'UPDATE ' . TBL_INVENTORY_FIELDS . ' SET inf_sequence = inf_sequence - 1 ...';
$this->db->queryPrepared($sql, ...);
// delete all data of this field in the item data table
$sql = 'DELETE FROM ' . TBL_INVENTORY_ITEM_DATA . ' WHERE ind_inf_id = ? -- $infId';
$this->db->queryPrepared($sql,…
- Record
GHSA-xw54-c3mx-9pm3- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N - Weakness
- CWE-1281, CWE-862
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
admidio/admidioPackagist |
through 5.0.9 | 5.0.10 |
admidio/admidioPackagist |
before 5.0.10, plus listed versions 4.1.04.1.3v4.2-Beta.1v4.2-Beta.2v4.2-Beta.3 Show 45 moreShow lessv4.2.0v4.2.1v4.2.10v4.2.11v4.2.12v4.2.13v4.2.14v4.2.2v4.2.3v4.2.4v4.2.5v4.2.6v4.2.7v4.2.8v4.2.9v4.3-Beta.1v4.3-Beta.3v4.3-Beta.4v4.3-Beta.5v4.3.0v4.3.1v4.3.10v4.3.11v4.3.12v4.3.13v4.3.14v4.3.15v4.3.16v4.3.17v4.3.2v4.3.3v4.3.4v4.3.5v4.3.6v4.3.7v4.3.8v4.3.9v5.0-Beta.1v5.0-Beta.2v5.0-Beta.3v5.0.0v5.0.1v5.0.2v5.0.3v5.0.4 |
5.0.10 |
History
| Recorded | Changed | Sources |
|---|---|---|
| aliases | EUVD | |
| first indexed | CVE List, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-47233 is a medium vulnerability (CVSS 6.5) in Admidio, published May 29, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.31%, the 24th percentile. Fixed in admidio/admidio 5.0.10.
References
github.com/Admidio/admidio/security/advisories/GHSA-xw54-c3mx-9pm3
github.com/Admidio/admidio/commit/d37ca6b27b9674238e58491cf7ba292e66898f15
github.com/advisories/GHSA-xw54-c3mx-9pm3
github.com/CVEProject/cvelistV5/tree/main/cves/2026/47xxx/CVE-2026-47233.json
nvd.nist.gov/vuln/detail/CVE-2026-47233
github.com/Admidio/admidio
Left out here: 5 versions and the rest of 2 source descriptions. The JSON record has them.