
Analisi difensiva, analisi dettagliata della patch e scanner di rilevamento per CVE-2026-14378 (WordPress DevKit Pro Plugin <= 2.3.0).
CVE-2026-14378 è un critico Bypass di autenticazione non autenticato (CVSS 9.8) nel plugin DevKit Pro per WordPress, che interessa tutte le versioni fino alla 2.3.0 inclusa.
Il plugin include un meccanismo di cambio utente per sviluppatori. Quando un amministratore "passa" a un altro account utente, memorizza l'ID dell'amministratore in un cookie denominato original_user_id. Il difetto: il plugin genera un form HTML di "switch back" su qualsiasi pagina ogni volta che quel cookie è presente — anche per i visitatori non autenticati che impostano manualmente il cookie. Peggio ancora, il passaggio di verifica del nonce controlla la capacità di amministratore dell'utente del cookie, non la sessione del chiamante — quindi il server consegna volentieri un cookie di sessione amministratore autenticato a chiunque invii il POST corretto.
Risultato netto: nessuna credenziale richiesta per il pieno takeover dell'amministratore di WordPress.
| Attributo | Dettagli |
|---|---|
| CVE ID | CVE-2026-14378 |
| Classe di vulnerabilità | Autenticazione impropria (CWE-287) |
| Punteggio CVSS v3.1 | 9.8 (Critico) |
| Vettore CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Software interessato | Plugin WordPress DevKit Pro (dplugins) |
| Versioni vulnerabili | <= 2.3.0 |
| Versione corretta | 2.3.1 |
| Data di divulgazione | 02 Ott 2026 |
DevKit Pro include un helper per sviluppatori che consente agli amministratori del sito di "passare" ad altri account utente per testare i permessi. Quando l'amministratore utilizza lo switch:
Set-Cookie: original_user_id=1isset($_COOKIE['original_user_id'])wp_footer() con un form POST nascosto contenente un nonce frescoadmin-post.php?action=revert_switchwp_set_auth_cookie($user_id) per ripristinare la sessione originaleIl gestore dell'hook wp_footer:
// DevKit Pro <= 2.3.0 — render_switch_back_bar()
public function render_switch_back_bar() {
// FLAW: Only checks if cookie exists — no session validation!
if ( isset( $_COOKIE['original_user_id'] ) ) {
$user_id = (int) $_COOKIE['original_user_id'];
$nonce = wp_create_nonce( 'devkit_revert_switch_' . $user_id );
echo '<div id="devkit-pro-switch-back" class="devkit-switch-bar" style="display:none;">';
echo ' <form id="devkit-revert-form" action="' . admin_url('admin-post.php') . '" method="POST">';
echo ' <input type="hidden" name="action" value="revert_switch" />';
echo ' <input type="hidden" name="_wpnonce" value="' . $nonce . '" />';
echo ' <input type="hidden" name="target_user_id" value="' . $user_id . '" />';
echo ' </form>';
echo '</div>';
echo '<!-- DevKit Pro 2.3.0 Switch Component Active -->';
}
}
Il gestore POST che elabora l'invio del modulo:
// DevKit Pro <= 2.3.0 — handle_revert_switch()
public function handle_revert_switch() {
$user_id = (int) $_POST['target_user_id'];
$nonce = sanitize_text_field( $_POST['_wpnonce'] );
if ( ! $this->verify_nonce_and_capability( $user_id, $nonce ) ) {
wp_die( 'Unauthorized' );
}
wp_set_current_user( $user_id );
wp_set_auth_cookie( $user_id ); // <-- Grants authenticated session to caller
wp_redirect( admin_url() );
exit;
}
private function verify_nonce_and_capability( $user_id, $nonce ) {
if ( ! wp_verify_nonce( $nonce, 'devkit_revert_switch_' . $user_id ) ) {
return false;
}
// CRITICAL FLAW: Checks the cookie user's capability, not the caller's!
return user_can( $user_id, 'manage_options' );
}
user_can( $user_id, 'manage_options' ) risponde alla domanda: "L'utente #1 ha la capability manage_options?"
La risposta per l'utente #1 (il primo amministratore WordPress creato) è sempre true.
Dovrebbe invece chiedere: "La persona che effettua questa richiesta HTTP ha la capability manage_options?"
Il controllo corretto è current_user_can('manage_options'), che restituirebbe false per un visitatore non autenticato.
L'intero walkthrough è stato eseguito e verificato su un'istanza WordPress live in esecuzione in un container Podman locale (http://localhost:8080) con DevKit Pro 2.3.0 attivo.
Per riprodurre tutto questo in locale, occorre:
Configurazione rapida del lab Podman:
# Start MariaDB
podman run -d --name wp-db \
-e MYSQL_ROOT_PASSWORD=rootpass \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wpuser \
-e MYSQL_PASSWORD=wppass \
mariadb:10.6
# Start WordPress
podman run -d --name wp-app \
-p 8080:80 \
--link wp-db:mysql \
-e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_DB_USER=wpuser \
-e WORDPRESS_DB_PASSWORD=wppass \
wordpress:latest
Dopo che WordPress è stato inizializzato (http://localhost:8080/wp-admin/install.php), installa e attiva DevKit Pro 2.3.0 tramite il menu dei plugin.