GitHub Security Advisory: GHSA-m9h6-8pqm-xrhf
Package: admidio/admidio (COMPOSER)
Severity: MODERATE (CVSS 4.5)
CWE: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Vulnerable versions: <= 5.0.8
Patched in: 5.0.9

Summary: Admidio has Path Traversal via Unvalidated `name` Parameter in Document Add Mode that Enables Arbitrary Server File Read

Details:
## Summary

The `add` mode in `modules/documents-files.php` accepts a `name` parameter validated only as `'string'` type (HTML encoding), allowing path traversal characters (`../`) to pass through unfiltered. Combined with the absence of CSRF protection on this endpoint and `SameSite=Lax` session cookies, a low-privileged attacker can trick a documents administrator into clicking a crafted link that registers an arbitrary server file (e.g., `install/config.php` containing database credentials) into a documents folder accessible to the attacker.

## Details

**Root cause — incorrect input validation type (modules/documents-files.php:222):**

```php
case 'add':
    $getName = admFuncVariableIsValid($_GET, 'name', 'string');
```

The `'string'` type in `admFuncVariableIsValid()` only applies `SecurityUtils::encodeHTML(StringUtils::strStripTags($value))` (system/bootstrap/function.php:414-416). Since `../` contains no HTML special characters (`<`, `>`, `&`, `"`, `'`), path traversal sequences pass through unchanged.

The correct type would be `'file'`, which calls `StringUtils::strIsValidFileName()` (src/Infrastructure/Utils/StringUtils.php:217-236). This function checks `basename($filename) !== $filename` at line 228, which would reject any path containing directory separators.

**Missing CSRF protection (modules/documents-files.php:221-238):**

```php
case 'add':
    $getName = admFuncVariableIsValid($_GET, 'name', 'string');

    if (!$gCurrentUser->isAdministratorDocumentsFiles()) {
        throw new Exception('SYS_NO_RIGHTS');
    }

    $folder = new Folder($gDb);
    $folder->readDataByUuid($getFolderUUID);
    $folder->addFolderOrFileToDatabase($getName);
    // ...
```

No `SecurityUtils::validateCsrfToken()` or form object validation. Compare with `folder_delete` (line 140) and `file_delete` (line 170) which both validate CSRF tokens. The `add` action operates entirely via GET parameters.

**Unsafe path construction (src/Documents/Entity/Folder.php:121-135):**

```php
public function addFolderOrFileToDatabase(string $newFolderFileName): void
{
    $newFolderFileName = urldecode($newFolderFileName);
    $newObjectPath = $this->getFullFolderPath() . '/' . $newFolderFileName;
    // ...
    if (is_file($newObjectPath)) {
        $newFile = new File($this->db);
        $newFile->setValue('fil_fol_id', $folderId);
        $newFile->setValue('fil_name', $newFolderFileName);  // traversal stored in DB
        // ...
        $newFile->save();
    }
}
```

No `realpath()` comparison or `basename()` check. The traversal filename (e.g., `../../../install/config.php`) is stored verbatim as `fil_name` in the database.

**File served on download (src/Documents/Entity/File.php:88-91, src/Documents/Service/DocumentsService.php:68-119):**

```php
// File.php:88-91
public function getFullFilePath(): string
{
    return $this->getFullFolderPath() . '/' . $this->getValue('fil_name', 'database');
}

// DocumentsService.php:75-118
$completePath = $file->getFullF