VYPR
Moderate severityNVD Advisory· Published Jan 22, 2022· Updated May 5, 2025

CVE-2022-23808

CVE-2022-23808

Description

An issue was discovered in phpMyAdmin 5.1 before 5.1.2. An attacker can inject malicious code into aspects of the setup script, which can allow XSS or HTML injection.

AI Insight

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

phpMyAdmin 5.1 before 5.1.2 allows XSS and HTML injection via insufficient input sanitization in the setup script.

Vulnerability

The vulnerability resides in the setup script of phpMyAdmin versions 5.1.0 and 5.1.1 (prior to 5.1.2). Insufficient filtering of query parameters and inadequate escaping of the action attribute in the configuration form allow an attacker to inject arbitrary HTML or JavaScript code. The setup script is accessible only if no config.inc.php file exists (i.e., the installation is not yet configured) [4].

Exploitation

An attacker can craft a malicious URL containing injected script or HTML in parameters such as formset or eol. When a victim with access to the setup script visits the crafted URL, the injected code executes in the context of the phpMyAdmin setup page. No authentication is required because the setup script is unauthenticated, but the attacker must convince the victim to visit the malicious link [1][4].

Impact

Successful exploitation leads to Cross-Site Scripting (XSS) or HTML injection, allowing the attacker to execute arbitrary JavaScript in the victim's browser. This could result in session hijacking, defacement, or other client-side attacks within the phpMyAdmin domain [4].

Mitigation

The issue is fixed in phpMyAdmin 5.1.2, released on 2022-01-10. Users should upgrade immediately. If upgrade is not possible, creating a config.inc.php file prevents access to the setup script, mitigating the attack. The fix includes commits 44eb12f and 5118acc in the official repository [1][3][4].

AI Insight generated on May 21, 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
phpmyadmin/phpmyadminPackagist
>= 5.1.0, < 5.1.25.1.2

Affected products

5

Patches

2
44eb12f15a56

Improve query params filtering in Setup pages

https://github.com/phpmyadmin/phpmyadminMaurício Meneghini FauthJan 13, 2022via ghsa
9 files changed · +48 82
  • libraries/classes/Controllers/Setup/ConfigController.php+6 3 modified
    @@ -5,8 +5,8 @@
     namespace PhpMyAdmin\Controllers\Setup;
     
     use PhpMyAdmin\Config\FormDisplayTemplate;
    -use PhpMyAdmin\Core;
     use PhpMyAdmin\Setup\ConfigGenerator;
    +use function is_string;
     
     class ConfigController extends AbstractController
     {
    @@ -17,6 +17,9 @@ class ConfigController extends AbstractController
          */
         public function index(array $params): string
         {
    +        $formset = isset($params['formset']) && is_string($params['formset']) ? $params['formset'] : '';
    +        $eol = isset($params['eol']) && $params['eol'] === 'win' ? 'win' : 'unix';
    +
             $pages = $this->getPages();
     
             $formDisplayTemplate = new FormDisplayTemplate($GLOBALS['PMA_Config']);
    @@ -34,13 +37,13 @@ public function index(array $params): string
             $config = ConfigGenerator::getConfigFile($this->config);
     
             return $this->template->render('setup/config/index', [
    -            'formset' => $params['formset'] ?? '',
    +            'formset' => $formset,
                 'pages' => $pages,
                 'form_top_html' => $formTop,
                 'fieldset_top_html' => $fieldsetTop,
                 'form_bottom_html' => $formBottom,
                 'fieldset_bottom_html' => $fieldsetBottom,
    -            'eol' => Core::ifSetOr($params['eol'], 'unix'),
    +            'eol' => $eol,
                 'config' => $config,
             ]);
         }
    
  • libraries/classes/Controllers/Setup/FormController.php+3 2 modified
    @@ -10,6 +10,7 @@
     use PhpMyAdmin\Setup\FormProcessing;
     use function ob_get_clean;
     use function ob_start;
    +use function is_string;
     
     class FormController extends AbstractController
     {
    @@ -22,7 +23,7 @@ public function index(array $params): string
         {
             $pages = $this->getPages();
     
    -        $formset = Core::isValid($params['formset'], 'scalar') ? $params['formset'] : null;
    +        $formset = isset($params['formset']) && is_string($params['formset']) ? $params['formset'] : '';
     
             $formClass = SetupFormList::get($formset);
             if ($formClass === null) {
    @@ -36,7 +37,7 @@ public function index(array $params): string
             $page = ob_get_clean();
     
             return $this->template->render('setup/form/index', [
    -            'formset' => $params['formset'] ?? '',
    +            'formset' => $formset,
                 'pages' => $pages,
                 'name' => $form::getName(),
                 'page' => $page,
    
  • libraries/classes/Controllers/Setup/HomeController.php+4 45 modified
    @@ -9,10 +9,8 @@
     use PhpMyAdmin\Config\ServerConfigChecks;
     use PhpMyAdmin\Core;
     use PhpMyAdmin\LanguageManager;
    -use PhpMyAdmin\Sanitize;
     use PhpMyAdmin\Setup\Index;
    -use function preg_replace;
    -use function uniqid;
    +use function is_string;
     
     class HomeController extends AbstractController
     {
    @@ -23,11 +21,9 @@ class HomeController extends AbstractController
          */
         public function index(array $params): string
         {
    -        $pages = $this->getPages();
    +        $formset = isset($params['formset']) && is_string($params['formset']) ? $params['formset'] : '';
     
    -        // Handle done action info
    -        $actionDone = Core::isValid($params['action_done'], 'scalar') ? $params['action_done'] : '';
    -        $actionDone = preg_replace('/[^a-z_]/', '', $actionDone);
    +        $pages = $this->getPages();
     
             // message handling
             Index::messagesBegin();
    @@ -53,43 +49,6 @@ public function index(array $params): string
             $text .= '</a>';
             Index::messagesSet('notice', 'no_https', __('Insecure connection'), $text);
     
    -        // Check for done action info and set notice message if present
    -        switch ($actionDone) {
    -            case 'config_saved':
    -                /* Use uniqid to display this message every time configuration is saved */
    -                Index::messagesSet(
    -                    'notice',
    -                    uniqid('config_saved'),
    -                    __('Configuration saved.'),
    -                    Sanitize::sanitizeMessage(
    -                        __(
    -                            'Configuration saved to file config/config.inc.php in phpMyAdmin '
    -                            . 'top level directory, copy it to top level one and delete '
    -                            . 'directory config to use it.'
    -                        )
    -                    )
    -                );
    -                break;
    -            case 'config_not_saved':
    -                /* Use uniqid to display this message every time configuration is saved */
    -                Index::messagesSet(
    -                    'notice',
    -                    uniqid('config_not_saved'),
    -                    __('Configuration not saved!'),
    -                    Sanitize::sanitizeMessage(
    -                        __(
    -                            'Please create web server writable folder [em]config[/em] in '
    -                            . 'phpMyAdmin top level directory as described in '
    -                            . '[doc@setup_script]documentation[/doc]. Otherwise you will be '
    -                            . 'only able to download or display it.'
    -                        )
    -                    )
    -                );
    -                break;
    -            default:
    -                break;
    -        }
    -
             Index::messagesEnd();
             $messages = Index::messagesShowHtml();
     
    @@ -205,7 +164,7 @@ public function index(array $params): string
             );
     
             return $this->template->render('setup/home/index', [
    -            'formset' => $params['formset'] ?? '',
    +            'formset' => $formset,
                 'languages' => $languages,
                 'messages' => $messages,
                 'servers_form_top_html' => $serversFormTopHtml,
    
  • libraries/classes/Controllers/Setup/ServersController.php+16 8 modified
    @@ -5,10 +5,12 @@
     namespace PhpMyAdmin\Controllers\Setup;
     
     use PhpMyAdmin\Config\Forms\Setup\ServersForm;
    -use PhpMyAdmin\Core;
     use PhpMyAdmin\Setup\FormProcessing;
     use function ob_get_clean;
     use function ob_start;
    +use function is_string;
    +use function is_numeric;
    +use function in_array;
     
     class ServersController extends AbstractController
     {
    @@ -19,12 +21,18 @@ class ServersController extends AbstractController
          */
         public function index(array $params): string
         {
    +        $formset = isset($params['formset']) && is_string($params['formset']) ? $params['formset'] : '';
    +        $id = isset($params['id']) && is_numeric($params['id']) && (int) $params['id'] >= 1 ? (int) $params['id'] : 0;
    +        $mode = '';
    +        if (isset($params['mode']) && in_array($params['mode'], ['add', 'edit', 'revert'], true)) {
    +            $mode = $params['mode'];
    +        }
    +
             $pages = $this->getPages();
     
    -        $id = Core::isValid($params['id'], 'numeric') ? (int) $params['id'] : null;
    -        $hasServer = ! empty($id) && $this->config->get('Servers/' . $id) !== null;
    +        $hasServer = $id >= 1 && $this->config->get('Servers/' . $id) !== null;
     
    -        if (! $hasServer && ($params['mode'] !== 'revert' && $params['mode'] !== 'edit')) {
    +        if (! $hasServer && $mode !== 'revert' && $mode !== 'edit') {
                 $id = 0;
             }
     
    @@ -33,10 +41,10 @@ public function index(array $params): string
             $page = ob_get_clean();
     
             return $this->template->render('setup/servers/index', [
    -            'formset' => $params['formset'] ?? '',
    +            'formset' => $formset,
                 'pages' => $pages,
                 'has_server' => $hasServer,
    -            'mode' => $params['mode'],
    +            'mode' => $mode,
                 'server_id' => $id,
                 'server_dsn' => $this->config->getServerDSN($id),
                 'page' => $page,
    @@ -48,9 +56,9 @@ public function index(array $params): string
          */
         public function destroy(array $params): void
         {
    -        $id = Core::isValid($params['id'], 'numeric') ? (int) $params['id'] : null;
    +        $id = isset($params['id']) && is_numeric($params['id']) && (int) $params['id'] >= 1 ? (int) $params['id'] : 0;
     
    -        $hasServer = ! empty($id) && $this->config->get('Servers/' . $id) !== null;
    +        $hasServer = $id >= 1 && $this->config->get('Servers/' . $id) !== null;
     
             if (! $hasServer) {
                 return;
    
  • libraries/classes/Setup/FormProcessing.php+11 5 modified
    @@ -8,10 +8,12 @@
     namespace PhpMyAdmin\Setup;
     
     use PhpMyAdmin\Config\FormDisplay;
    -use PhpMyAdmin\Core;
     use PhpMyAdmin\Response;
     use PhpMyAdmin\Template;
     use PhpMyAdmin\Url;
    +use function in_array;
    +use function is_string;
    +use function is_numeric;
     
     /**
      * PhpMyAdmin\Setup\FormProcessing class
    @@ -52,10 +54,14 @@ public static function process(FormDisplay $form_display)
             }
     
             // form has errors, show warning
    -        $page = $_GET['page'] ?? '';
    -        $formset = $_GET['formset'] ?? '';
    -        $formId = Core::isValid($_GET['id'], 'numeric') ? $_GET['id'] : '';
    -        if ($formId === null && $page === 'servers') {
    +        $page = 'index';
    +        if (isset($_GET['page']) && in_array($_GET['page'], ['form', 'config', 'servers'], true)) {
    +            $page = $_GET['page'];
    +        }
    +
    +        $formset = isset($_GET['formset']) && is_string($_GET['formset']) ? $_GET['formset'] : '';
    +        $formId = isset($_GET['id']) && is_numeric($_GET['id']) && (int) $_GET['id'] >= 1 ? (int) $_GET['id'] : 0;
    +        if ($formId === 0 && $page === 'servers') {
                 // we've just added a new server, get its id
                 $formId = $form_display->getConfigFile()->getServerCount();
             }
    
  • phpstan-baseline.neon+0 5 modified
    @@ -270,11 +270,6 @@ parameters:
     			count: 1
     			path: libraries/classes/Controllers/Setup/HomeController.php
     
    -		-
    -			message: "#^Parameter \\#1 \\$server of method PhpMyAdmin\\\\Config\\\\ConfigFile\\:\\:getServerDSN\\(\\) expects int, int\\|null given\\.$#"
    -			count: 1
    -			path: libraries/classes/Controllers/Setup/ServersController.php
    -
     		-
     			message: "#^Comparison operation \"\\>\" between 0 and 0 is always false\\.$#"
     			count: 1
    
  • psalm-baseline.xml+0 8 modified
    @@ -446,9 +446,6 @@
         </PossiblyNullArrayAccess>
       </file>
       <file src="libraries/classes/Controllers/Setup/FormController.php">
    -    <PossiblyNullArgument occurrences="1">
    -      <code>$formset</code>
    -    </PossiblyNullArgument>
         <UndefinedClass occurrences="1">
           <code>new $formClass($this-&gt;config)</code>
         </UndefinedClass>
    @@ -461,11 +458,6 @@
           <code>PMA_IS_WINDOWS</code>
         </TypeDoesNotContainType>
       </file>
    -  <file src="libraries/classes/Controllers/Setup/ServersController.php">
    -    <PossiblyNullArgument occurrences="1">
    -      <code>$id</code>
    -    </PossiblyNullArgument>
    -  </file>
       <file src="libraries/classes/Controllers/Table/ChangeController.php">
         <PossiblyNullArgument occurrences="1">
           <code>$where_clause ?? null</code>
    
  • setup/index.php+3 5 modified
    @@ -27,10 +27,9 @@
         Core::fatalError(__('Configuration already exists, setup is disabled!'));
     }
     
    -$page = Core::isValid($_GET['page'], 'scalar') ? (string) $_GET['page'] : '';
    -$page = preg_replace('/[^a-z]/', '', $page);
    -if ($page === '') {
    -    $page = 'index';
    +$page = 'index';
    +if (isset($_GET['page']) && in_array($_GET['page'], ['form', 'config', 'servers'], true)) {
    +    $page = $_GET['page'];
     }
     
     Core::noCacheHeader();
    @@ -77,6 +76,5 @@
     $controller = new HomeController($GLOBALS['ConfigFile'], new Template());
     echo $controller->index([
         'formset' => $_GET['formset'] ?? null,
    -    'action_done' => $_GET['action_done'] ?? null,
         'version_check' => $_GET['version_check'] ?? null,
     ]);
    
  • templates/setup/servers/index.twig+5 1 modified
    @@ -11,6 +11,10 @@
       <h2>{% trans 'Add a new server' %}</h2>
     {% endif %}
     
    -{{ page|raw }}
    +{% if mode == 'add' or mode == 'edit' or mode == 'revert' %}
    +  {{ page|raw }}
    +{% else %}
    +  <p>{% trans 'Something went wrong.' %}</p>
    +{% endif %}
     
     {% endblock %}
    
5118acce1dfc

Escape config-form's action attribute

https://github.com/phpmyadmin/phpmyadminMaurício Meneghini FauthJan 13, 2022via ghsa
3 files changed · +5 5
  • templates/config/form_display/form_top.twig+1 1 modified
    @@ -1,4 +1,4 @@
    -<form method="{{ method }}" action="{{ action|raw }}" class="config-form disableAjax">
    +<form method="{{ method }}" action="{{ action|e('html_attr') }}" class="config-form disableAjax">
       <input type="hidden" name="tab_hash" value="">
       {% if has_check_page_refresh %}
         <input type="hidden" name="check_page_refresh" id="check_page_refresh" value="">
    
  • test/classes/Config/FormDisplayTemplateTest.php+3 3 modified
    @@ -38,13 +38,13 @@ protected function setUp(): void
          */
         public function testDisplayFormTop(): void
         {
    -        $_SERVER['REQUEST_URI'] = 'https://www.phpmyadmin.net';
    +        $_SERVER['REQUEST_URI'] = 'https://www.phpmyadmin.net/index.php?key=value&key2=">value2';
             $GLOBALS['cfg']['ServerDefault'] = '';
             $result = $this->formDisplayTemplate->displayFormTop(null, 'posted', [1]);
     
             $this->assertStringContainsString(
    -            '<form method="get" action="https://www.phpmyadmin.net" ' .
    -            'class="config-form disableAjax">',
    +            '<form method="get" action="https&#x3A;&#x2F;&#x2F;www.phpmyadmin.net&#x2F;'
    +            . 'index.php&#x3F;key&#x3D;value&amp;key2&#x3D;&quot;&gt;value2" class="config-form disableAjax">',
                 $result
             );
     
    
  • test/classes/Config/PageSettingsTest.php+1 1 modified
    @@ -54,7 +54,7 @@ public function testShowGroupBrowse(): void
                 '<div id="page_settings_modal">'
                 . '<div class="page_settings">'
                 . '<form method="post" '
    -            . 'action="index.php?db=db&server=1&lang=en" '
    +            . 'action="index.php&#x3F;db&#x3D;db&amp;server&#x3D;1&amp;lang&#x3D;en" '
                 . 'class="config-form disableAjax">',
                 $html
             );
    

Vulnerability mechanics

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

References

8

News mentions

0

No linked articles in our index yet.