VYPR
High severityNVD Advisory· Published Feb 9, 2026· Updated Feb 10, 2026

Adminer has an Unauthenticated Persistent DoS via Array Injection in ?script=version Endpoint

CVE-2026-25892

Description

Adminer is open-source database management software. Adminer v5.4.1 and earlier 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. Upgrade to Adminer 5.4.2.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Adminer 5.4.1 and earlier are vulnerable to an unauthenticated persistent denial-of-service via array injection into the version check endpoint.

Adminer, an open-source database management tool, contains a denial-of-service (DoS) vulnerability in its version check mechanism. The endpoint ?script=version is designed to receive signed version data from adminer.org via JavaScript postMessage, which is then stored on the server for verification [1][2]. This endpoint lacks origin validation and accepts POST data from any source, including array parameters [2].

An unauthenticated attacker can exploit this by sending a POST request with the parameter version[] instead of version. PHP converts this to an array, which is then serialized and written to the /tmp/adminer.version file. On subsequent page loads, subsequent page loads, the code attempts to pass this array to the openssl_verify() function, which expects a string, resulting in a TypeError and causing an HTTP 500 error for all users [2][3]. No prior authentication or specific network position is required, making the attack surface broad [1].

The vulnerability leads to a persistent denial-of-service condition, impacting the availability of the Adminer application for all users. The crash occurs every time a page is loaded, as the malformed version file is read [2]. There is no data integrity or confidentiality impact, but the service becomes unavailable [2].

The issue is fixed in Adminer version 5.4.2 [4]. Users who cannot immediately upgrade can mitigate the risk by making the temporary directory (usually the value of upload_tmp_dir) unwritable by the web server, preventing the malicious file writing [2].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
vrana/adminerPackagist
>= 4.6.2, < 5.4.25.4.2

Affected products

2
  • Adminer/Adminerllm-create
    Range: <=5.4.1
  • vrana/adminerv5
    Range: >= 4.6.2, < 5.4.2

Patches

1
21d3a3150388

Avoid denial-of-service via version check (GHSA-q4f2-39gr-45jh, regression from 4.6.2)

https://github.com/vrana/adminerJakub VranaFeb 8, 2026via ghsa
5 files changed · +12 52
  • adminer/include/bootstrap.inc.php+0 10 modified
    @@ -29,16 +29,6 @@
     	include "../adminer/file.inc.php";
     }
     
    -if ($_GET["script"] == "version") {
    -	$filename = get_temp_dir() . "/adminer.version";
    -	@unlink($filename); // it may not be writable by us, @ - it may not exist
    -	$fp = file_open_lock($filename);
    -	if ($fp) {
    -		file_write_unlock($fp, serialize(array("signature" => $_POST["signature"], "version" => $_POST["version"])));
    -	}
    -	exit;
    -}
    -
     // Adminer doesn't use any global variables; they used to be declared here
     
     if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility
    
  • adminer/include/design.inc.php+3 19 modified
    @@ -62,24 +62,8 @@ function page_header(string $title, string $error = "", $breadcrumb = array(), s
     	adminer()->bodyClass();
     	echo "'>\n";
     	$filename = get_temp_dir() . "/adminer.version";
    -	if (!$_COOKIE["adminer_version"] && function_exists('openssl_verify') && file_exists($filename) && filemtime($filename) + 86400 > time()) { // 86400 - 1 day in seconds
    -		$version = unserialize(file_get_contents($filename));
    -		$public = "-----BEGIN PUBLIC KEY-----
    -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwqWOVuF5uw7/+Z70djoK
    -RlHIZFZPO0uYRezq90+7Amk+FDNd7KkL5eDve+vHRJBLAszF/7XKXe11xwliIsFs
    -DFWQlsABVZB3oisKCBEuI71J4kPH8dKGEWR9jDHFw3cWmoH3PmqImX6FISWbG3B8
    -h7FIx3jEaw5ckVPVTeo5JRm/1DZzJxjyDenXvBQ/6o9DgZKeNDgxwKzH+sw9/YCO
    -jHnq1cFpOIISzARlrHMa/43YfeNRAm/tsBXjSxembBPo7aQZLAWHmaj5+K19H10B
    -nCpz9Y++cipkVEiKRGih4ZEvjoFysEOdRLj6WiD/uUNky4xGeA6LaJqh5XpkFkcQ
    -fQIDAQAB
    ------END PUBLIC KEY-----
    -";
    -		if (openssl_verify($version["version"], base64_decode($version["signature"]), $public) == 1) {
    -			$_COOKIE["adminer_version"] = $version["version"]; // doesn't need to send to the browser
    -		}
    -	}
     	echo script("mixin(document.body, {onkeydown: bodyKeydown, onclick: bodyClick"
    -		. (isset($_COOKIE["adminer_version"]) ? "" : ", onload: partial(verifyVersion, '" . VERSION . "', '" . js_escape(ME) . "', '" . get_token() . "')")
    +		. (isset($_COOKIE["adminer_version"]) ? "" : ", onload: partial(verifyVersion, '" . VERSION . "')")
     		. "});
     document.body.classList.replace('nojs', 'js');
     const offlineMessage = '" . js_escape(lang('You are offline.')) . "';
    @@ -153,8 +137,8 @@ function csp(): array {
     	return array(
     		array(
     			"script-src" => "'self' 'unsafe-inline' 'nonce-" . get_nonce() . "' 'strict-dynamic'", // 'self' is a fallback for browsers not supporting 'strict-dynamic', 'unsafe-inline' is a fallback for browsers not supporting 'nonce-'
    -			"connect-src" => "'self'",
    -			"frame-src" => "https://www.adminer.org",
    +			"connect-src" => "'self' https://www.adminer.org",
    +			"frame-src" => "'none'",
     			"object-src" => "'none'",
     			"base-uri" => "'none'",
     			"form-action" => "'self'",
    
  • adminer/static/functions.js+7 21 modified
    @@ -96,29 +96,15 @@ function cookie(assign, days) {
     
     /** Verify current Adminer version
     * @param string
    -* @param string own URL base
    -* @param string
     */
    -function verifyVersion(current, url, token) {
    +function verifyVersion(current) {
     	cookie('adminer_version=0', 1);
    -	const iframe = document.createElement('iframe');
    -	iframe.src = 'https://www.adminer.org/version/?current=' + current;
    -	iframe.frameBorder = 0;
    -	iframe.marginHeight = 0;
    -	iframe.scrolling = 'no';
    -	iframe.style.width = '7ex';
    -	iframe.style.height = '1.25em';
    -	iframe.style.display = 'none';
    -	addEventListener('message', event => {
    -		if (event.origin == 'https://www.adminer.org') {
    -			const match = /version=(.+)/.exec(event.data);
    -			if (match) {
    -				cookie('adminer_version=' + match[1], 1);
    -				ajax(url + 'script=version', () => { }, event.data + '&token=' + token);
    -			}
    -		}
    -	}, false);
    -	qs('#version').appendChild(iframe);
    +	// do not send X-Requested-With to avoid preflight
    +	fetch('https://www.adminer.org/version/?current=' + current).then(async response => {
    +		const json = await response.json();
    +		cookie('adminer_version=' + (json.version || current), 7); // empty if there's no newer version
    +		qs('#version').textContent = json.version;
    +	});
     }
     
     /** Get value of select
    
  • CHANGELOG.md+1 0 modified
    @@ -1,4 +1,5 @@
     ## Adminer dev
    +- Avoid denial-of-service via version check (GHSA-q4f2-39gr-45jh, regression from 4.6.2)
     - Pretty print JSON in edit
     - Support multiline generated values in alter table
     - Link //domain.tld values
    
  • plugins/version-github.php+1 2 modified
    @@ -11,13 +11,12 @@ class AdminerVersionGithub extends Adminer\Plugin {
     	function head($dark = null) {
     		?>
     <script <?php echo Adminer\nonce(); ?>>
    -verifyVersion = (current, url, token) => {
    +verifyVersion = current => {
     	// dummy value to prevent repeated verifications after AJAX failure
     	cookie('adminer_version=0', 1);
     	ajax('https://api.github.com/repos/vrana/adminer/releases/latest', request => {
     		const response = JSON.parse(request.responseText);
     		const version = response.tag_name.replace(/^v/, '');
    -		// we don't save to adminer.version because the response is not signed; also GitHub can handle our volume of requests
     		// we don't display the version here because we don't have version_compare(); design.inc.php will display it on the next load
     		cookie('adminer_version=' + version, 1);
     	}, null, null);
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.