Безопасность серверного кода WordPress опирается на модель нулевого доверия (Zero-Trust Input Architecture): любые входящие данные из суперглобальных массивов ($_GET, $_POST, $_COOKIE), REST API запросов или метаданных считаются потенциально вредоносными. В традиционном стеке статический анализ безопасности (SAST) выполняется с помощью правил PHP_CodeSniffer (WordPress Coding Standards). Однако регулярные выражения и базовые синтаксические снифферы не способны отслеживать контекстный граф потока данных (Data Flow Graph, DFG) и генерируют огромное количество ложных срабатываний (false positives) либо пропускают сложные цепочки передачи параметров через замыкания и сервисные слои (false negatives).
Применение специализированных AI-агентов на базе LLM в сочетании с парсерами абстрактного синтаксического дерева (AST, например nikic/php-parser) кардинально меняет парадигму аудита безопасности:
$_POST['user_input']) через промежуточные трансформации до опасного стока (Sink: $wpdb->query(), echo, unserialize()).$wpdb->prepare(), добавлением криптографических Nonce-токенов и реализацией принципа позднего экранирования (Late Escaping).Векторная модель аудита базируется на сопоставлении источника уязвимости, фильтров санитизации и стока исполнения.
[ ИСТОЧНИК (Source) ] : $_POST, $_GET, REST payload, XML-RPC
|
v
[ ПРОВЕРКА ПОЛНОМОЧИЙ ] : current_user_can() + wp_verify_nonce()
|
+---[ Ошибка: Нет проверки ] ---> CRITICAL: Privilege Escalation / CSRF
|
v
[ САНИТИЗАЦИЯ (Sanitization) ] : sanitize_text_field(), absint()
|
v
[ ИСПОЛНЕНИЕ / СТОК (Sink) ]
|
+---> База данных : $wpdb->prepare() [Защита от SQLi]
+---> Вывод в DOM : esc_html(), esc_attr(), wp_kses() [Защита от XSS]
+---> Файловая с-ма: validate_file(), wp_upload_bits() [Защита от RCE]Преобразование исходного кода плагина в абстрактное синтаксическое дерево через AST-парсер.
Идентификация источников пользовательского ввода (Sources) и потенциально опасных приемников (Sinks).
Инференс ИИ-модели для проверки наличия промежуточной санитизации и проверки прав.
Создание диффа с внедрением prepare, проверки nonce и функций экранирования.
Запуск Pest/PHPUnit тестов для подтверждения сохранения бизнес-логики после применения патча.
current_user_can().wp-content/plugins при интеграции нового вендорского софта для обнаружения недекларированных бэкдоров и уязвимостей нулевого дня.permission_callback во всех зарегистрированных маршрутах register_rest_route(), исключающая открытые эндпоинты с мутирующими операциями.Ниже представлен реальный производственный сервис на PHP 8.4, моделирующий работу AI-агента безопасности для инспекции и автоматического устранения SQL-инъекций и CSRF уязвимостей в обработчиках форм.
<?php
declare(strict_types=1);
/**
* Author: Artur Yusupov (Fullstack Agentic Lab)
* Package: @agentic-lab/security-auditor
* Standard: WordPress 6.8+ / PHP 8.4 Strict
*/
namespace AgenticLab\SecurityAudit;
use wpdb;
use WP_Error;
final readonly class SecurityAuditorEngine
{
public function __construct(
private wpdb $db,
private string $securityLogGroup = 'agentic-audit'
) {}
/**
* Пример уязвимого кода (До аудита):
*
* public function legacy_delete_customer(): void {
* $id = $_POST['customer_id'];
* $this->db->query("DELETE FROM {$this->db->prefix}customers WHERE id = " . $id);
* }
*/
/**
* Эталонный безопасный обработчик, сформированный AI-агентом после аудита.
*
* @param array<string, mixed> $requestData Массив входных данных ($_POST)
* @return true|WP_Error Результат операции
*/
public function secureDeleteCustomer(array $requestData): true|WP_Error
{
// 1. Проверка авторизации и матрицы прав (Capabilities)
if (!current_user_can('manage_options')) {
$this->logSecurityViolation('unauthorized_deletion_attempt', 'User lacks manage_options capability');
return new WP_Error(
'rest_forbidden',
__('Недостаточно привилегий для выполнения операции.', 'agentic-lab'),
['status' => 403]
);
}
// 2. Валидация криптографического токена Nonce (Защита от CSRF)
$nonce = isset($requestData['_wpnonce']) && is_string($requestData['_wpnonce'])
? sanitize_text_field(wp_unslash($requestData['_wpnonce']))
: '';
if ($nonce === '' || !wp_verify_nonce($nonce, 'agentic_delete_customer_action')) {
$this->logSecurityViolation('csrf_detected', 'Invalid or missing CSRF nonce');
return new WP_Error(
'rest_invalid_nonce',
__('Сессия истекла или запрос не прошел проверку безопасности.', 'agentic-lab'),
['status' => 403]
);
}
// 3. Строгая санитизация и приведение типов (Type Casting)
$rawId = $requestData['customer_id'] ?? null;
$customerId = filter_var($rawId, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
if ($customerId === false) {
return new WP_Error(
'rest_invalid_param',
__('Идентификатор клиента должен быть натуральным числом.', 'agentic-lab'),
['status' => 400]
);
}
// 4. Подготовленное выражение $wpdb->prepare() (Защита от SQL-инъекций)
$table = $this->db->prefix . 'agentic_customers';
// Внимание: имя таблицы экранируется валидацией структуры, литерал параметризуется %d
$preparedSql = $this->db->prepare(
"DELETE FROM {$table} WHERE id = %d AND status != %s",
$customerId,
'protected'
);
if ($preparedSql === null) {
return new WP_Error('db_prepare_failed', __('Сбой подготовки SQL запроса.', 'agentic-lab'), ['status' => 500]);
}
$result = $this->db->query($preparedSql);
if ($result === false) {
return new WP_Error('db_query_error', __('Ошибка при удалении записи из БД.', 'agentic-lab'), ['status' => 500]);
}
return true;
}
/**
* Безопасный рендеринг пользовательского контента с принципом Late Escaping.
*/
public function renderCustomerProfile(int $customerId, string $rawBio, string $homepageUrl): string
{
// Позднее экранирование строго по контексту HTML-атрибутов и тегов
$safeId = esc_attr((string) $customerId);
$safeUrl = esc_url($homepageUrl);
$safeBioText = wp_kses_post($rawBio); // Разрешает безопасный HTML контента
return sprintf(
'<div class="customer-card" data-customer-id="%s">' .
'<p class="customer-bio">%s</p>' .
'<a href="%s" class="customer-site" target="_blank" rel="noopener noreferrer">%s</a>' .
'</div>',
$safeId,
$safeBioText,
$safeUrl,
esc_html__('Перейти на сайт', 'agentic-lab')
);
}
private function logSecurityViolation(string $eventType, string $description): void
{
error_log(sprintf(
'[%s] [SECURITY ALERT] Type: %s | Details: %s | IP: %s | UserID: %d',
$this->securityLogGroup,
$eventType,
$description,
sanitize_text_field($_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'),
get_current_user_id()
));
}
}Симптом: Скрытые логические уязвимости и обход фильтров при приведении типов MySQL (Type Juggling).
Причина: Разработчик пишет WHERE id = %s, передавая строку '1 OR 1=1'. Хотя prepare экранирует кавычки, использование строкового спецификатора для чисел снижает строгость и производительность индексов БД.
Решение: Для целочисленных первичных и внешних ключей всегда использовать строго %d, а для чисел с плавающей точкой — %f.
Симптом: Авторизованный пользователь с ролью Subscriber (подписчик) может удалить данные интернет-магазина через POST-запрос, перехватив валидный Nonce страницы.
Причина: Разработчик полагается исключительно на wp_verify_nonce(), забывая вызвать current_user_can('manage_options'). Nonce защищает исключительно от CSRF (подделки клика извне), но не является механизмом проверки прав доступа!
Решение: Всегда выполнять двойную проверку: сначала current_user_can(), затем wp_verify_nonce().
Симптом: В базе данных появляются испорченные строки вида &lt;script&gt;, ломающие поиск и REST API.
Причина: Применение esc_html() или esc_attr() перед вызовом $wpdb->insert() или update_post_meta().
Решение: В базу данных сохраняются сырые, но санитизированные данные (sanitize_text_field()). Экранирование (esc_html, esc_url) применяется исключительно в момент вывода в браузер (Late Escaping).
Симптом: Критическая уязвимость удаленного выполнения кода (Remote Code Execution, RCE) через POP-цепочки классов ядра или плагинов.
Причина: Обработка cookies, webhook payload или параметров формы через нативный PHP unserialize().
Решение: Использовать json_encode() и json_decode() со строгим флагом JSON_THROW_ON_ERROR. Если десериализация WordPress-структур неизбежна, использовать maybe_unserialize() с предварительной проверкой is_serialized().
Сбор всех PHP-файлов плагина и извлечение графа вызовов функций (Call Graph).
Локализация прямых запросов $wpdb, вызовов eval, unserialize и вывода без esc_*.
Проверка прохождения входных аргументов от точки входа до точки сохранения/вывода.
Формирование типобезопасного кода с prepare, проверками прав и модульными тестами.