Admidio: Any logged-in user can delete inventory fields via mode=field_delete — incomplete fix of #2024
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.
modules/inventory.php mode dispatch at the top of the file:
```php
// 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:
```php
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:
```php
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:
```php
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:
```php
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, array($infId));
// delete all data of this field in the field select options table
$sql = 'DELETE FROM ' . TBL_INVENTORY_FIELD_OPTIONS . ' WHERE ifo_inf_id = ? -- $infId';
$this->db->queryPrepared($sql, array($infId));
$return = parent::delete(); // DELETE FROM adm_inventory_fields WHERE inf_id = ?
$this->db->endTransaction();
return $return;
}
```
Compare with ItemField::save() at line 230, which *does* enforce admin:
```php
public function save(bool $updateFingerPrint = true): bool
{
global $gCurrentUser, $gCurrentOrgId;
// only administrators can edit item fields
if (!$gCurrentUser->isAdministrator() && !$this->saveChangesWithoutRights) {
throw new Exception('Item field could not be saved because only administrators are allowed to edit item fields.');
}
...
}
```
The asymmetry is the bug: save is gated, delete is not.
This issue can be reached over the network, attack complexity is low, an attacker needs low-level privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality none, integrity high, availability none.
The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
CVE-2026-47233 is classified as CWE-1281: Sequence of Processor Instructions Leads to Unexpected Behavior. Specific combinations of processor instructions lead to undesirable behavior such as locking the processor until a hard reset performed.
CVE-2026-47233 is recorded against 2 packages.
Published on 29 May 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.
github.com (Web)
github.com (Package)
admidio/admidio has other advisories on record. If you are patching this one, these are worth checking on the same host:
These advisories are the same class of weakness (CWE-1281: Sequence of Processor Instructions Leads to Unexpected Behavior) in other software:
Details
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| admidio/admidio | — | 5.0.10 |
| unknown | — | — |
References
Similar Threats
Vulnerability Monitoring
CVE-2026-47233 is rated CVSS 6.5 Medium. BotEraser monitors your WordPress installation and notifies you when software you use appears in our vulnerability database.
Set Up Free Alerts →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.
Stay up to date with the latest from Boteraser.
We use cookies to improve your experience on our site. By using our site, you consent to cookies.
Manage your cookie preferences below:
Essential cookies enable basic functions and are necessary for the proper function of the website.
CloudFlare provides web performance and security solutions, enhancing site speed and protecting against threats.
Service URL: developers.cloudflare.com (opens in a new window)
These cookies are needed for adding comments on this website.
These cookies are used for managing login functionality on this website.
Statistics cookies collect information anonymously. This information helps us understand how visitors use our website.
Google Analytics is a powerful tool that tracks and analyzes website traffic for informed marketing decisions.
Service URL: policies.google.com (opens in a new window)
You can find more information in our Cookie Policy and Privacy Policy.