
Защитный анализ, разбор патча и сканер обнаружения для CVE-2026-14378 (WordPress DevKit Pro Plugin <= 2.3.0).
CVE-2026-14378 — это критический обход аутентификации без учётных данных (CVSS 9.8) в плагине DevKit Pro для WordPress, затрагивающий все версии до 2.3.0 включительно.
Плагин включает механизм переключения пользователей для разработчиков. Когда администратор «переключается» на другую учётную запись, плагин сохраняет ID администратора в cookie с именем original_user_id. Изъян: плагин отображает HTML-форму «переключиться обратно» на любой странице всякий раз, когда этот cookie присутствует — в том числе для неаутентифицированных посетителей, которые устанавливают cookie вручную. Хуже того, этап проверки nonce проверяет административные права пользователя из cookie, а не сессии вызывающего — поэтому сервер охотно выдаёт аутентифицированный cookie административной сессии любому, кто отправит правильный POST.
Итог: для полного захвата администратора WordPress не требуется никаких учётных данных.
| Атрибут | Детали |
|---|---|
| CVE ID | CVE-2026-14378 |
| Класс уязвимости | Некорректная аутентификация (CWE-287) |
| Оценка CVSS v3.1 | 9.8 (критическая) |
| Вектор CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Затронутое ПО | Плагин DevKit Pro (dplugins) для WordPress |
| Уязвимые версии | <= 2.3.0 |
| Исправленная версия | 2.3.1 |
| Дата раскрытия | 02 окт. 2026 |
DevKit Pro включает инструмент для разработчиков, позволяющий администраторам сайта «переключаться» на другие учётные записи для проверки прав. Когда администратор использует переключение:
Set-Cookie: original_user_id=1isset($_COOKIE['original_user_id'])wp_footer() со скрытой POST-формой, содержащей свежий nonceadmin-post.php?action=revert_switchwp_set_auth_cookie($user_id) для восстановления исходной сессииОбработчик хука 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 -->';
}
}
Обработчик POST, который обрабатывает отправку формы:
// 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' ) отвечает на вопрос: «Обладает ли пользователь #1 возможностью manage_options?»
Ответ для пользователя #1 (первого созданного администратора WordPress) всегда true.
Следовало бы спрашивать: «Обладает ли лицо, выполняющее этот HTTP-запрос, возможностью manage_options?»
Правильная проверка — current_user_can('manage_options'), которая вернула бы false для неаутентифицированного посетителя.
Весь этот разбор был выполнен и проверен на работающем экземпляре WordPress в локальном контейнере Podman (http://localhost:8080) с активным DevKit Pro 2.3.0.
Чтобы воспроизвести это локально, вам понадобится:
Быстрая настройка лаборатории на 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
После инициализации WordPress (http://localhost:8080/wp-admin/install.php) установите и активируйте DevKit Pro 2.3.0 через меню плагинов.
Перед отправкой любой полезной нагрузки атаки убедитесь, что плагин присутствует, и определите его версию, запросив readme плагина:
Запрос:
GET /wp-content/plugins/devkit-pro/readme.txt HTTP/1.1
Host: localhost:8080