The Fileeditor controller defines a hiddenItems array containing security-sensitive paths (.env, composer.json, vendor/, .git/) but only enforces this protection in the listFiles() method. The readFile(), saveFile(), deleteFileOrFolder(), renameFile(), createFile(), and createFolder() endpoints perform no hidden items validation, allowing direct API access to files that are intended to be protected. A backend user with only fileeditor.read permission can exfiltrate application secrets from .env, and a user with fileeditor.update permission can overwrite composer.json to achieve remote code execution.
The hiddenItems array is defined at modules/Fileeditor/Controllers/Fileeditor.php:10-26:
protected $hiddenItems = [
'.git', '.github', '.idea', '.vscode',
'node_modules', 'vendor', 'writable',
'.env', 'env', 'composer.json', 'composer.lock',
'tests', 'spark', 'phpunit.xml.dist', 'preload.php'
];
This array is checked only in listFiles() at lines 45-48 and 64:
// Line 45-48 - path component check
foreach ($pathParts as $part) {
if (in_array($part, $this->hiddenItems)) {
return $this->failForbidden();
}
}
// Line 64 - directory listing filter
if (in_array($name, $this->hiddenItems)) continue;
However, readFile() (line 76) performs neither a hiddenItems check nor an allowedFileTypes() check:
public function readFile()
{
// ... validation ...
$path = $this->request->getVar('path');
$fullPath = realpath(ROOTPATH . $path);
if (!$fullPath || !is_file($fullPath) || strpos($fullPath, realpath(ROOTPATH)) !== 0) {
return $this->response->setJSON(['error' => '...'])->setStatusCode(400);
}
return $this->response->setJSON(['content' => file_get_contents($fullPath)]);
}
This means any file within ROOTPATH — regardless of extension (.php, .env, etc.) — can be read by any user with the...
0.31.4.0Exploitability
AV:NAC:LPR:HUI:NScope
S:UImpact
C:HI:HA:L6.7/CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:L