Oct 30, 2026·8 min read·4 visits
An unauthenticated remote attacker can pass an array parameter (`version[]=...`) to the `?script=version` endpoint in AdminNeo (< 5.5.0). The injected array is cached on disk for 24 hours and subsequently passed to `rawurlencode()`, triggering an unhandled PHP 8 `TypeError` and resulting in an application-wide HTTP 500 Denial of Service.
AdminNeo versions 4.6.2 through 5.4.1 contain an improper input validation vulnerability (CWE-20) in the version verification endpoint (?script=version). An unauthenticated remote attacker can submit a crafted HTTP POST request containing an array parameter for 'version', which is serialized into a shared server-side temporary cache file without type checking or authentication. On subsequent requests, the application deserializes this cached array and passes it to cookie() and rawurlencode(), triggering an uncaught fatal TypeError in PHP 8.x environments and causing a persistent 24-hour Denial of Service (DoS) for all users.
AdminNeo is an open-source, web-based database management tool written in PHP, created as a fork of Adminer. To notify administrators of available software updates, AdminNeo implements an asynchronous version check mechanism. In versions 4.6.2 prior to 5.5.0, this mechanism relies on client-side JavaScript querying the GitHub Releases API and forwarding the discovered version tag back to the AdminNeo server via the ?script=version endpoint.
The server processes requests to ?script=version inside admin/include/bootstrap.inc.php prior to executing authentication or Cross-Site Request Forgery (CSRF) verification routines. The endpoint extracts the $_POST["version"] parameter and writes it directly into a serialized temporary file (adminneo.version) located in the system temporary directory. This file serves as a shared cache across all user sessions for 24 hours (86,400 seconds).
Because the endpoint fails to validate that the incoming version parameter is a scalar string, an unauthenticated attacker can supply an array payload using PHP's bracket parameter syntax (e.g., version[]=INJECTED). PHP parses this input into an array structure and persists the serialized array into the shared cache file.
When subsequent requests arrive from any client lacking the neo_version cookie, admin/include/design.inc.php reads and deserializes the poisoned cache file. The deserialized array is passed directly to the cookie() helper function and subsequently to PHP's internal rawurlencode() function. Under PHP 8.x strict type enforcement, passing an array to rawurlencode() raises an unhandled TypeError exception, terminating execution with an HTTP 500 response across the entire instance.
The root cause of CVE-2026-59978 is a combination of missing authentication, missing CSRF token validation, and improper input type validation (CWE-20) within the bootstrap request lifecycle. In admin/scripts/functions.js, the intended client workflow constructs a POST body containing both the version string and a CSRF token (version=' + version + '&token=' + token). However, the server-side handler in admin/include/bootstrap.inc.php ignores the token parameter entirely.
In PHP, when an HTTP POST body contains parameter names ending in square brackets (version[]=value), the PHP SAPI automatically populates $_POST["version"] as an indexed or associative array rather than a string. Because bootstrap.inc.php does not enforce scalar validation via is_string() or explicit type casting, the call to serialize(["version" => $_POST["version"]]) succeeds and stores the nested array inside get_temp_dir() . "/adminneo.version".
The secondary trigger occurs during standard page rendering in admin/include/design.inc.php. When page_header() executes, it checks if version verification is enabled (isVersionVerificationEnabled()) and whether the incoming request lacks the neo_version cookie. If the /tmp/adminneo.version file exists and its modification timestamp is less than 86,400 seconds old, the application reads the file and calls unserialize().
The extracted $data["version"] value—now an array—is passed to cookie("neo_version", $data["version"], $lifetime). In admin/include/functions.inc.php, the cookie() function is defined with a strict parameter type signature (function cookie(string $name, string $value, int $lifetime = 2592000): void) or passes $value directly into rawurlencode($value). In PHP 8.0 and later, internal string functions and typed user functions throw a fatal TypeError when given an array, halting script execution before any HTML output or login interface can be rendered.
In vulnerable versions of AdminNeo (>= 4.6.2, < 5.5.0), the request routing in admin/include/bootstrap.inc.php intercepts ?script=version before session initialization:
// admin/include/bootstrap.inc.php (Vulnerable)
if ($_GET["script"] == "version") {
$filename = get_temp_dir() . "/adminneo.version";
@unlink($filename); // It may not be writable by us, @ - it may not exist.
$file = open_file_with_lock($filename);
if ($file) {
// FLAW: $_POST["version"] is not validated as a string and no CSRF/auth check is performed
write_and_unlock_file($file, serialize(["version" => $_POST["version"]]));
}
exit;
}During subsequent requests, admin/include/design.inc.php retrieves this cached data inside page_header():
// admin/include/design.inc.php (Vulnerable)
if (Admin::get()->getConfig()->isVersionVerificationEnabled()) {
$filename = get_temp_dir() . "/adminneo.version";
if (!isset($_COOKIE["neo_version"]) && file_exists($filename) && ($lifetime = filemtime($filename) + 86400 - time()) > 0) {
$data = unserialize(file_get_contents($filename));
$_COOKIE["neo_version"] = $data["version"];
// CRASH: $data["version"] is an array, causing a TypeError in cookie() / rawurlencode()
cookie("neo_version", $data["version"], $lifetime);
}
}In commit b7ae929e6afb374f0a7aba3d73b7d441470ff907 (ported from upstream Adminer commit 21d3a3150388677b18647d68aec93b7850e457d3), the maintainers remediated the vulnerability by completely removing the server-side version caching mechanism rather than adding input sanitization.
--- a/admin/include/bootstrap.inc.php
+++ b/admin/include/bootstrap.inc.php
@@ -41,17 +41,6 @@
// Compiled files loading.
include __DIR__ . "/../file.inc.php";
-if ($_GET["script"] == "version") {
- $filename = get_temp_dir() . "/adminneo.version";
- @unlink($filename); // It may not be writable by us, @ - it may not exist.
-
- $file = open_file_with_lock($filename);
- if ($file) {
- write_and_unlock_file($file, serialize(["version" => $_POST["version"]]));
- }
- exit;
-}
-
if (!$_SERVER["REQUEST_URI"]) { // IIS 5 compatibility
$_SERVER["REQUEST_URI"] = $_SERVER["ORIG_PATH_INFO"];
}
@@ -100,6 +89,9 @@
cookie("neo_import", "", -3600);
}
+// Remove unused file.
+@unlink(get_temp_dir() . "/adminneo.version");
+
include __DIR__ . "/../core/Locale.php";--- a/admin/scripts/functions.js
+++ b/admin/scripts/functions.js
@@ -113,11 +113,7 @@ function verifyVersion(baseUrl, token) {
const matches = response.tag_name.match(/^v(\d{1,2}\.\d{1,2}\.\d{1,2}(-(alpha|beta|rc)\d?)?)$/);
if (!matches) return;
- const version = matches[1];
- cookie('neo_version=' + version, 1);
-
- const data = 'version=' + version + '&token=' + token;
- ajax(baseUrl + 'script=version', null, data);
+ cookie('neo_version=' + matches[1], 1);
}, null, null, true);
});
}> [!NOTE]
> Fix Completeness Assessment: The patch is complete and eliminates the attack surface entirely. By removing the ?script=version endpoint, deleting the unserialize() call in design.inc.php, and adding @unlink(get_temp_dir() . "/adminneo.version"); in bootstrap.inc.php, upgrading to version 5.5.0 both prevents future exploitation and automatically cleans up any pre-existing poisoned cache file on the first post-upgrade request.
Exploitation of CVE-2026-59978 requires no authentication, session state, or specialized tooling. The only prerequisite is network access to the AdminNeo web interface and that version verification remains enabled in the AdminNeo configuration (which is enabled by default).
First, an attacker or auditor can verify that the target AdminNeo instance is operational by issuing a standard HTTP GET request:
curl -s -o /dev/null -w "%{http_code}\n" "http://target-host:8080/"
# Output: 200To poison the shared version cache, the attacker sends a single HTTP POST request to ?script=version with an array parameter version[]:
curl -X POST "http://target-host:8080/?script=version" -d "version[]=INJECTED"The server responds with an empty HTTP 200 status and writes the serialized payload a:1:{s:7:"version";a:1:{i:0;s:8:"INJECTED";}} to /tmp/adminneo.version. Immediately following this request, any user visiting the application without an existing neo_version browser cookie will trigger the crash:
curl -s -o /dev/null -w "%{http_code}\n" "http://target-host:8080/"
# Output: 500On the server side, the PHP error log records the following fatal exception:
Fatal error: Uncaught TypeError: rawurlencode(): Argument #1 ($string) must be of type string, array given in admin/include/functions.inc.phpThe primary impact of CVE-2026-59978 is a persistent, application-wide Denial of Service (DoS). Once the /tmp/adminneo.version file is poisoned, every unauthenticated or newly arriving user session attempting to load the AdminNeo login screen or dashboard encounters an unhandled HTTP 500 Internal Server Error.
Because the cache expiration window is hardcoded to 86,400 seconds (filemtime($filename) + 86400 - time()), a single HTTP POST request renders the application unavailable for 24 hours unless an administrator manually intervenes to delete the temporary file. Furthermore, an attacker can automate a single request per day (or every few minutes) to sustain an indefinite outage.
The vulnerability is rated with a CVSS v3.1 Base Score of 7.5 (High) under the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H:
unserialize() is invoked on the cache file contents, the input passed to serialize() during cache creation is wrapped in an array (["version" => $_POST["version"]]) and serialized by PHP itself. Because $_POST only contains strings and arrays parsed from the HTTP request body, arbitrary PHP Object Injection is not achievable through this vector.Administrators and developers using adminneo-org/adminneo should upgrade immediately to version 5.5.0 or later. Version 5.5.0 removes the vulnerable server-side caching endpoint and automatically unlinks any existing /tmp/adminneo.version file during bootstrap execution.
For environments where an immediate upgrade is not feasible, administrators can apply the following workarounds to neutralize the vulnerability:
/tmp/adminneo.version file owned by root with read-only permissions (0444). Because bootstrap.inc.php suppresses unlink errors (@unlink($filename)) and checks if the file can be opened for writing, preventing the web server user (www-data, nginx, or apache) from modifying the file stops cache poisoning:rm -f /tmp/adminneo.version
touch /tmp/adminneo.version
chown root:root /tmp/adminneo.version
chmod 0444 /tmp/adminneo.version(Ensure /tmp matches the directory returned by PHP's sys_get_temp_dir() or upload_tmp_dir directive.)
?script=version at the Reverse Proxy / Web Server: Configure Nginx or Apache to reject any HTTP request containing script=version in the query string:# Nginx block rule
if ($arg_script = "version") {
return 403;
}# Apache mod_rewrite block rule
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)script=version(&|$) [NC]
RewriteRule .* - [F,L]versionVerification to false in the configuration array passed to AdminNeo.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
AdminNeo adminneo-org | >= 4.6.2, < 5.5.0 | 5.5.0 |
| Attribute | Detail |
|---|---|
| Vulnerability Type | CWE-20: Improper Input Validation (Type Confusion / DoS) |
| CVSS v3.1 Score | 7.5 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) |
| Attack Vector | Network (Unauthenticated HTTP POST to ?script=version) |
| Affected Versions | adminneo-org/adminneo >= 4.6.2, < 5.5.0 |
| Patched Version | 5.5.0 |
| Impact | Persistent 24-hour application-wide HTTP 500 Denial of Service |
| Exploit Status | Public Proof-of-Concept (PoC) available |
| CISA KEV Status | Not Listed |
The product receives input or data, but does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.
An OS command injection and argument injection vulnerability exists in the Nx build system and its official Maven (@nx/maven) and Gradle (@nx/gradle) plugins. When constructing the project dependency graph, the plugins invoke underlying Java build wrappers via subshells while interpolating unsanitized plugin options directly from nx.json into the command arguments. An attacker who supplies a crafted nx.json file via a repository or pull request can execute arbitrary shell commands with the privileges of the user or CI/CD runner invoking any Nx command that computes the project graph.
Charmbracelet Soft Serve versions 0.5.0 through 0.12.2 contain an authorization bypass and observable response discrepancy vulnerability in the HTTP Git server. Remote attackers can determine the existence, exact names, and clone URLs of private repositories by issuing crafted Go remote import path discovery requests (?go-get=1) or by observing differential HTTP status codes across Git Smart HTTP, Dumb HTTP, and Git LFS endpoints.
A Time-of-Check to Time-of-Use (TOCTOU) race condition in Charmbracelet Soft Serve versions 0.6.0 through 0.12.2 allows unauthenticated users to retain read access to repositories after their visibility is changed from public to private. The flaw stems from premature cache invalidation in the SetPrivate method prior to committing the visibility update to the underlying database. Concurrent read requests arriving during the database transaction window repopulate the non-expiring in-memory LRU cache with stale public metadata, bypassing access controls across HTTP, SSH, and Git protocols until the server process is restarted.
A resource consumption vulnerability exists in the Authlib joserfc Python library prior to version 1.7.5. When processing JSON Web Encryption (JWE) objects formatted using General JSON Serialization, the library fails to enforce an upper bound on the number of elements within the recipients array. An unauthenticated attacker can supply a JWE containing thousands of recipient entries targeting an RSA key management algorithm, forcing the server to perform an equivalent number of computationally expensive RSA private-key decryption operations per request and exhausting available CPU resources.
CVE-2026-119284 (GHSA-9pg5-8c7x-5hfx) is an uncontrolled resource consumption vulnerability (CWE-400) in the compact serialization deserialization routines of joserfc prior to version 1.7.6. The library enforced individual segment size limits only after invoking Python's bytes.split(b'.') on untrusted input tokens. By sending oversized compact JWS or JWE tokens, an unauthenticated remote attacker can force the Python interpreter to duplicate and allocate memory for every segment before size validation executes, resulting in memory exhaustion and an Endpoint Denial of Service (DoS).
An improper input validation vulnerability (CWE-20) exists in the Entity Syntax Tree (EST) JSON deserialization component of the Cedar Policy Language (`cedar-policy` and `@cedar-policy/cedar-wasm`). When parsing JSON-formatted policy templates that define `is ... in` scope constraints on `principal` or `resource`, the parser used wildcard pattern matching that ignored the provided slot identifier (`?principal` or `?resource`). This omission allows malformed JSON templates to bypass initial deserialization validation, resulting in either a runtime panic during template linking or inverted slot bindings that alter authorization outcomes.