01개요
Elementor는 워드프레스(WordPress)용 드래그앤드롭 페이지 빌더 플러그인으로, 2022년 기준 500만 개 이상의 사이트에 설치돼 워드프레스 플러그인 생태계에서 가장 널리 쓰이는 축에 속합니다. 3.6.0 버전부터 Elementor는 플러그인을 처음 설치한 관리자를 위한 '온보딩(onboarding) 마법사' — 사이트 이름·로고 설정, 테마 활성화, Elementor Pro 업그레이드 등을 안내하는 초기 설정 화면 — 을 추가했습니다.
이 온보딩 마법사가 서버와 통신하는 방식(AJAX 액션 처리)에 문제가 있었습니다. 온보딩 모듈은 요청에 담긴 nonce(위조요청방지 토큰, CSRF 토큰)가 유효한지만 확인하고, 그 요청을 보낸 사용자가 애초에 이 기능을 쓸 권한이 있는지는 확인하지 않았습니다. 두 검사는 목적이 다릅니다 — nonce는 '이 요청이 우리가 렌더링한 페이지에서 온 것이 맞는가'를 증명할 뿐, '이 사용자가 관리자인가'는 증명하지 않습니다. 그런데 이 nonce가 권한과 무관하게 모든 로그인 사용자에게 뿌려지고 있었기 때문에, 사실상 두 검사가 하나로 뭉개진 셈이 됐습니다.
그 결과, 사이트에 계정만 있으면(예: 오픈 회원가입, 댓글 작성용 계정, WooCommerce 고객 계정 등으로 만들어지는 최하위 권한 Subscriber) 사이트 이름·로고를 마음대로 바꾸는 것을 넘어, elementor_upload_and_install_pro 액션으로 임의의 zip 파일을 '플러그인'으로 위장해 업로드·설치·활성화시킬 수 있었습니다. 업로드한 zip 안에 PHP 코드를 심어두면 그 코드가 곧바로 서버에서 실행되므로, 최하위 권한 계정 하나로 사이트 전체를 장악하는 원격 코드 실행(RCE)까지 이어집니다.
CVSS: 8.8 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) — NVD의 공식 산정이며, 흥미롭게도 Wordfence 본인이 CNA(CVE 번호 발급 기관) 자격으로 NVD에 제출한 값도 동일하게 8.8/S:U입니다(NVD API로 직접 확인). 다만 Wordfence가 자사 소비자용 threat-intel 취약점 데이터베이스 페이지에서는 이 CVE를 9.9(CRITICAL)로 별도 표기하고 있다고 여러 2차 소스(SentinelOne 등)가 인용합니다 — 저희는 봇 차단(자동화 접근 차단)으로 그 페이지 원문을 직접 열람·대조하지 못했고, 인용된 벡터 문자열(S:C 추정)도 byte-level로 확인하지 못했습니다 — 이 9.9 수치는 미검증 2차 인용으로 남겨둡니다. 이 글은 NVD가 직접 확인해 주는 8.8을 공식값으로 씁니다. CWE-862(Missing Authorization) + CWE-434(Unrestricted Upload of File with Dangerous Type).
이 근본원인은 온보딩 모듈이 처음 도입된 3.6.0(GitHub 태그 커밋 기준 2022-03-21)부터 존재했고, 3.6.3(2022-04-12, GitHub 태그 커밋 557eff68475cc9ff8e05880ff00301418902cddc 기준)에서 패치됐습니다. NVD 등록일은 2022-04-19입니다. 신고·발견은 Wordfence Threat Intelligence(연구원 Ramuel Gall)가 했고, 비슷한 시기 별도 업체 Plugin Vulnerabilities도 독립적으로 같은 문제를 공개했습니다(§References). 이 근본원인을 별도로 쪼갠 variant CVE는 확인되지 않았습니다 — 이 CVE 하나가 대표합니다.
02영향받는 버전
| 대상 | 취약 버전 | 안전 버전 |
|---|---|---|
| Elementor Website Builder(무료판, wordpress.org 배포) | 3.6.0 ~ 3.6.2 (온보딩 모듈이 도입된 버전부터) | 3.6.3 이상 |
| Elementor Pro | 이 CVE의 취약 대상 자체는 아님 — 다만 upload_and_install_pro 액션이 흉내 내는 설치 대상 이름이 elementor-pro라, 이 취약점의 실제 공격 벡터(위장 플러그인 zip)에 이름이 등장합니다. | 해당 없음 |
03배경 — nonce는 신원증명이 아니다
워드프레스에는 검증 목적이 서로 다른 두 가지 보안 장치가 있습니다. nonce(wp_verify_nonce())는 위조요청방지(CSRF) 토큰으로, '이 요청이 정말 우리가 방금 렌더링한 페이지에서 보낸 것인가'만 증명합니다 — 페이지를 볼 수 있는 사람이면 누구나 그 페이지 안에 박힌 nonce를 손에 넣습니다. 반면 capability 검사(current_user_can())는 '이 사용자가 이 작업을 할 권한이 실제로 있는가'를 확인합니다. 워드프레스 공식 문서와 개발 가이드는 두 검사를 항상 함께 쓰라고 명시합니다 — nonce만으로는 '누가' 요청했는지 전혀 알 수 없기 때문입니다.
Elementor 3.6.0의 온보딩 모듈은 이 관례에서 벗어난 방식으로 AJAX 요청을 처리했습니다. 워드프레스 표준 방식은 wp_ajax_{action} 훅에 핸들러를 등록하는 것인데(이 경우에도 개발자가 직접 capability를 확인해야 하는 건 동일합니다), 온보딩 모듈은 대신 admin_init 훅에 익명 함수를 걸어 두고 그 함수 안에서 $_POST['action']과 nonce를 직접 검사한 뒤, 통과하면 자체 스위치문으로 여러 기능을 라우팅하는 방식을 썼습니다. 이 자체는 문제가 아닙니다 — 문제는 이 관문에서 확인한 게 nonce 하나뿐이었다는 점입니다.
이 nonce가 어떻게 발급·배포되는지가 다음 절의 단서입니다. Elementor는 Ajax라는 공용(common) 모듈을 통해 nonce를 만들고, 이 모듈은 특정 권한을 가진 사용자에게만이 아니라 로그인한 모든 사용자에게 조건 없이 로드됩니다.
04취약점 발생 원인
이 취약점은 '누가 요청했는가'와 '요청한 사람이 이걸 할 자격이 있는가'를 같은 질문으로 취급한 데서 시작합니다. 관리자 전용 기능의 관문에 권한 검사가 아예 없었던 것(W1)과, 그 관문을 여는 유일한 열쇠(nonce)가 애초에 모든 로그인 사용자에게 조건 없이 배포되고 있었던 것(W2)이 만나 완성됩니다.
1"관리자 전용 기능인데, nonce만 확인하고 신원(권한)은 확인하지 않았다"
온보딩 모듈의 admin_init 훅 콜백이 wp_doing_ajax()·$_POST['action'] 존재·wp_verify_nonce() 세 조건만 통과하면 maybe_handle_ajax()를 호출해, 사이트 이름 변경부터 임의 플러그인 zip 설치까지 이어지는 스위치문 전체를 열어줬습니다.
Module::__construct()는 admin_init 액션에 익명 함수를 등록합니다. 이 함수는 요청이 AJAX 요청인지, action·_nonce POST 파라미터가 있는지, 그리고 그 nonce가 Ajax::NONCE_KEY('elementor_ajax') 기준으로 유효한지만 확인합니다. 이 네 조건이 전부 참이면 곧바로 $this->maybe_handle_ajax()를 호출합니다 — 요청자가 관리자인지, 심지어 Elementor를 편집할 권한이라도 있는지는 어디에서도 묻지 않습니다.
Elementor 실제 소스 — core/app/modules/onboarding/module.php · Module::__construct() (패치 전, GitHub 커밋 e66df28f9c7c65b85e3262f4006821621233b876 = v3.6.2 태그). 438행이 nonce만 확인하고 끝나는 지점입니다 — current_user_can() 호출이 없습니다.
maybe_handle_ajax()는 $_POST['action'] 문자열 하나로 사이트 이름 변경(elementor_update_site_name)·로고 변경(elementor_update_site_logo·elementor_upload_site_logo)·테마 활성화(elementor_activate_hello_theme)·그리고 Elementor Pro 업로드·설치(elementor_upload_and_install_pro)까지 7가지 액션 중 하나로 라우팅합니다. 이 라우팅 지점에도 권한 재확인은 없습니다 — 앞의 관문 하나만 통과하면 7개 액션 전부가 열립니다.
왜 이렇게 됐나nonce 검증 함수의 이름(wp_verify_nonce) 자체에 '검증'이 들어 있다 보니, 코드를 훑어볼 때 '요청이 검증됐다'는 인상을 줍니다. 하지만 이 함수가 증명하는 건 요청의 출처일 뿐 요청자의 자격이 아닙니다. 이 코드는 그 둘을 구분하는 두 번째 질문(권한이 있는가)을 아예 던지지 않았습니다.
2"그 nonce 자체가, 권한과 무관하게 모든 로그인 사용자에게 뿌려지고 있었다"
elementor_ajax nonce를 발급하는 Ajax 공용 모듈은 App::init_components()에서 어떤 조건도 없이 추가되는 반면, 관리자 권한이 필요한 Finder 모듈은 명시적으로 current_user_can( 'manage_options' ) 뒤에서만 추가됩니다 — 같은 함수 안에서 Elementor 개발자 스스로 '이 모듈은 권한 게이트가 필요하다'와 '이 모듈은 필요 없다'를 갈랐는데, Ajax가 후자로 분류된 것입니다.
Ajax 모듈의 get_init_settings()는 'nonce' => $this->create_nonce()를 반환하고, 이 값은 매 wp-admin 페이지 로드마다 elementorCommon이라는 이름의 JS 설정 객체로 페이지 소스에 그대로 박혀 브라우저로 전달됩니다. 이 로직 자체는 로그인 여부만 확인하면 되는 기능(예: 검색 자동완성)을 염두에 뒀을 수 있지만, W1의 관문이 바로 이 nonce 하나로 관리자 전용 기능까지 열어주면서 문제가 커졌습니다.
Elementor 실제 소스 — core/common/app.php · App::init_components() (v3.6.2 태그, 커밋 e66df28f9c7c65b85e3262f4006821621233b876). 58행(Ajax, 무조건 추가)과 60~64행(Finder, manage_options 조건부 추가)의 대비가 핵심입니다.
실제로 App::init_components()를 보면, Elementor 개발자들은 이미 '권한이 필요한 모듈'과 '필요 없는 모듈'을 구분해 코드를 짜 놓았습니다. Ajax 모듈은 조건 없이 추가되고, 그 바로 다음 줄의 Finder(검색) 모듈만 current_user_can( 'manage_options' ) 뒤에 조건부로 추가됩니다. 즉 '권한 게이트가 필요한 자산은 이렇게 막는다'는 패턴이 같은 함수 안에 이미 있었는데, 온보딩 모듈이 기대는 Ajax의 nonce에는 그 패턴이 적용되지 않았습니다.
왜 이렇게 됐나이 코드는 '이 자산이 새어나가면 위험한가'라는 질문에 Finder에는 그렇다고 답하고 Ajax에는 아니라고 답한 결과입니다. Ajax 모듈이 처음 설계될 당시(2.0.0, 2018년경)에는 이 nonce로 열리는 기능들이 대부분 저권한 사용자가 써도 무방한 것들이었을 가능성이 있습니다 — 하지만 이후 온보딩 모듈처럼 이 nonce 하나로 관리자 전용 기능까지 열어주는 코드가 얹히면서, 애초의 '이건 안전하다'는 전제가 조용히 깨졌습니다.
무게 중심은 W1(온보딩 모듈이 관리자 전용 기능의 관문에 권한 검사를 두지 않은 것)입니다 — 이게 없었다면 W2는 무해했습니다.
W2(Ajax 공용 nonce가 모든 로그인 사용자에게 배포되는 것)는 그 자체로는 설계상 결함이 아닙니다 — Ajax 모듈이 처음 만들어질 때 전제했던 위험도로는 합리적이었을 수 있고, 이 nonce에 기대는 다른 코드들은 실제로 저권한 사용자가 써도 되는 기능일 수 있습니다. W1이 이 nonce의 권한 범위를 온보딩의 관리자 전용 기능까지 확장해서 쓰지만 않았다면 문제가 되지 않았습니다.
한 문장으로 묶으면 이렇습니다. '요청이 위조되지 않았다(nonce)'와 '요청자가 이걸 할 자격이 있다(capability)'는 서로 다른 질문인데, 이 코드는 앞의 질문에 대한 답만으로 뒤의 질문까지 답했다고 처리했습니다. 그 틈에서 최하위 권한 계정이 관리자 전용 기능의 문을 그대로 열었습니다.
05공격 과정
5.1 공격 과정 요약
- 공격자가 대상 사이트에 아무 권한이나(오픈 회원가입, 댓글용 계정, WooCommerce 고객 계정 등으로 만들어지는 Subscriber 등급) 로그인된 계정을 확보합니다.
- 그 계정으로
/wp-admin/의 아무 페이지나 방문해, 페이지 소스에 박힌elementorCommonJS 설정 객체에서elementor_ajaxnonce 값을 읽어옵니다 — 이 nonce는 권한과 무관하게 모든 로그인 사용자에게 동일하게 제공됩니다(W2). - 이 nonce와
action=elementor_upload_and_install_pro, 그리고 위조한 zip 파일을/wp-admin/admin-ajax.php로 POST 전송합니다. - 온보딩 모듈의
admin_init훅이 nonce만 확인하고 통과시켜(W1)maybe_handle_ajax()를 호출하고,action문자열에 따라upload_and_install_pro()로 라우팅합니다. upload_and_install_pro()가 업로드된 파일을Plugin_Upgrader::install()로 그대로 설치하고, 곧이어WP_PLUGIN_DIR . '/elementor-pro/elementor-pro.php'경로를activate_plugin()으로 활성화합니다.- zip 안에 표준 플러그인 헤더를 갖춘
elementor-pro.php가 들어 있으면, 워드프레스는 이를 정상 플러그인으로 인식해 그 안의 PHP 코드를 서버에서 그대로 실행합니다 — 최하위 권한 계정으로 시작한 요청이 서버 임의 코드 실행으로 끝납니다.
5.2 상세 공격 과정
가장 낮은 진입장벽은 nonce를 손에 넣는 단계입니다. Elementor의 Ajax 모듈이 만드는 elementor_ajax nonce는 관리자 화면을 렌더링할 때마다 elementorCommon이라는 JS 전역 설정 객체 안에 평문으로 들어가는데, 이 객체는 로그인한 사용자의 권한 등급과 무관하게 페이지 소스에 그대로 박힙니다. 즉 공격자는 별도의 취약점 없이, 자기 계정으로 /wp-admin/ 아무 페이지나 열어 소스 보기만 하면 이 값을 얻습니다.
이 nonce를 손에 넣은 뒤에는 /wp-admin/admin-ajax.php로 action=elementor_upload_and_install_pro, _nonce=<획득한 값>, fileToUpload=<zip 파일>을 담아 POST 요청을 보냅니다(공개된 PoC 구조를 개념적으로만 서술 — 실제 요청 형식·구체 파라미터 조합은 이 글에 싣지 않습니다). 이 요청이 admin_init 훅에 도달하면, W1에서 짚은 대로 nonce 검증만 통과하면 그대로 maybe_handle_ajax()가 호출되고, $_POST['action'] 값에 따라 upload_and_install_pro()로 라우팅됩니다.
upload_and_install_pro()는 업로드된 파일을 검증 없이 Plugin_Upgrader 인스턴스의 $upgrader->install( $_FILES['fileToUpload']['tmp_name'], [ 'overwrite_package' => false ] )에 넘깁니다. 이 함수는 워드프레스가 '정식 플러그인 zip 설치'에 쓰는 표준 API로, zip 압축을 풀어 wp-content/plugins/ 아래에 배치합니다. 뒤이어 코드는 그 결과가 성공이면 activate_plugin( WP_PLUGIN_DIR . '/elementor-pro/elementor-pro.php', false, false, true )를 호출해 정확히 이 경로의 파일을 즉시 활성화합니다. 다시 말해 공격자가 만든 zip이 elementor-pro/elementor-pro.php라는 경로 구조와, 워드프레스가 플러그인으로 인식하는 데 필요한 최소한의 헤더 주석만 갖추면, 그 안의 임의 PHP 코드가 활성화 시점에 서버에서 실행됩니다.
이 지점부터는 일반적인 워드프레스 플러그인 백도어 기법(웹셸, 관리자 계정 생성 등)과 다르지 않습니다 — 그 후속 활용 절차는 이 글에서 다루지 않습니다(무해화).
5.3 미흡점 ↔ 공격 흐름 매핑
| 미흡점(§4) | 발화 지점(§5.2) | 여는 프리미티브 | → 다음으로 잇는 것 |
|---|---|---|---|
| W2 — Ajax 공용 nonce가 모든 로그인 사용자에게 배포 | nonce 획득 단계(§8.2 1문단, 다이어그램 A→B) | 권한 등급과 무관하게 유효한 elementor_ajax nonce 확보 | W1의 유일한 관문을 통과할 재료 확보 |
| W1 — admin_init 관문이 nonce만 확인하고 capability는 확인 안 함 | onboarding admin_init 훅 도달 시점(§8.2 2문단, 다이어그램 C→D) | 관리자 전용 스위치문(maybe_handle_ajax) 전체에 도달 | elementor_upload_and_install_pro 액션까지 라우팅 |
| (귀결) 검증 없는 플러그인 설치·활성화 | upload_and_install_pro()의 Plugin_Upgrader::install()·activate_plugin() 호출(§8.2 3문단, 다이어그램 E) | 위조 zip이 정식 플러그인 경로로 배치·활성화 | 서버에서 임의 PHP 코드 실행(RCE) |
06취약점 패치
왜§7 W1에서 지목한 자리 — 관리자 전용 스위치문 전체로 통하는 단 하나의 관문 — 를 정확히 겨냥한 수정입니다. nonce 검증 조건 뒤에 && current_user_can( 'manage_options' )를 추가해, 이 관문을 통과하려면 이제 관리자 권한이 있어야만 하도록 만들었습니다.
어떻게패치는 7개 온보딩 액션마다 개별 권한을 매핑하는 대신, 이 모든 액션이 공유하는 단 하나의 관문에 가장 강한 권한(manage_options, 관리자급) 하나를 요구하는 방식을 택했습니다 — 사이트 이름 바꾸기처럼 상대적으로 가벼운 기능까지도 전부 관리자만 쓸 수 있게 됩니다. 정교함보다 확실함을 택한, 빠르고 거친(coarse) 수정입니다.
비고바로 다음 버전인 3.6.4(GitHub 태그 커밋 d30e5a5860685f2d48ce7278f0d582624af1abee)에서 Elementor는 이 관문을 각 액션에 맞는 개별 capability로 다시 나눴습니다 — 로고 변경은 edit_theme_options, 테마 활성화는 switch_themes, Pro 설치는 install_plugins와 activate_plugins 둘 다로. 또한 사이트 로고 변경 로직에 첨부 ID 존재 확인(wp_get_attachment_url())과 정수 강제(absint())를 추가하는 등 입력 검증도 함께 다듬었습니다. 이건 3.6.3의 수정이 이 CVE를 못 막았다는 뜻이 아니라 — manage_options는 Subscriber를 포함한 모든 저권한 등급을 이미 배제하므로 CVE-2022-1329의 공격 경로는 3.6.3에서 완전히 막힙니다 — 급하게 막은 방어선을 다음 릴리스에서 제품 품질 수준으로 다듬은 후속 조치로 읽는 게 정확합니다.
07대응방안
가장 확실한 조치는 Elementor를 3.6.3 이상으로 업데이트하는 것입니다(§영향받는 버전 표). 이후 릴리스(3.6.4)는 세분화된 권한 검사와 입력 검증을 추가로 포함하므로, 가능하면 3.6.4 이상을 권장합니다.
- 즉시 업데이트가 어렵다면, 이 취약점은 어떤 등급이든 로그인 계정만 있으면 트리거되므로 오픈 회원가입·불필요한 저권한 계정 발급 경로를 임시로 잠그는 것이 공격 표면을 크게 줄입니다.
- WAF·리버스 프록시 규칙으로
/wp-admin/admin-ajax.php요청 중action파라미터가elementor_update_site_name·elementor_update_site_logo·elementor_upload_site_logo·elementor_update_data_sharing·elementor_activate_hello_theme·elementor_upload_and_install_pro·elementor_update_onboarding_option중 하나이면서 요청자가 관리자 세션이 아닌 경우를 차단하는 규칙을 임시로 걸 수 있습니다(온보딩이 이미 끝난 사이트라면 이 액션들 자체를 전면 차단해도 무방합니다). - 역할 관리 플러그인 등으로 Subscriber를 포함한 저권한 역할에서
wp-admin접근 자체를 최소화하거나, 최소한 파일 업로드가 필요 없는 역할에는 관련 권한을 추가로 제거하는 것도 방어 심층화(defense in depth)로 유효합니다. - 탐지 관점. 접근 로그·인증 로그에서
action=elementor_로 시작하는admin-ajax.php요청을 관리자가 아닌 낮은 권한 사용자 세션이 보낸 이력이 있는지 확인합니다. 또한 정상적인 구매·배포 절차 없이wp-content/plugins/elementor-pro(또는 낯선 플러그인 폴더)가 새로 생성됐는지,elementor_onboarded옵션 값이 예상치 못한 시점에 바뀌었는지를 파일 무결성 모니터링·워드프레스 옵션 감사로 관찰하는 것이 탐지 관점에서 유효합니다.
08왜 이게 반복되는가
이 사건이 흥미로운 이유는, 취약해진 코드가 새로 짠 복잡한 로직이 아니라 워드프레스에서 가장 기본적인 관용구(nonce + capability)의 절반만 가져다 썼다는 점입니다. 저희가 Jenkins CLI 임의 파일 읽기(CVE-2024-23897)에서 짚은 것과 뿌리가 비슷합니다 — 거기서는 '로컬 신뢰를 전제로 설계된 인자 파서'가 원격 노출 컨텍스트로 옮겨지며 인가 검사가 다시 검토되지 않았고, 여기서는 'CSRF 방지용 nonce'가 '신원·권한 증명'으로 슬쩍 격상돼 쓰였습니다. WSO2 API Manager의 JWT 서명검증 우회 사례에서도 '검증하는 코드가 있다'는 사실 자체가 '검증이 실제로 인가 기능을 한다'는 보장이 아니었다는 같은 계열의 교훈을 다뤘습니다 — 세 사건 모두 검증 로직이 존재는 했지만, 그 검증이 실제로 막아야 할 질문을 막지 못했습니다.
패치완전성 관점에서도 이 사건은 배울 점이 있습니다. 3.6.3의 수정은 정교하지 않았습니다 — 7개 액션을 하나의 최고 권한으로 뭉뚱그렸으니까요. 하지만 그 거칢이 오히려 안전한 방향의 거칢이었습니다(과잉 차단이지 과소 차단이 아니었습니다). 다음 릴리스에서 세분화하며 코드 품질을 다듬은 것은 '급한 불부터 확실하게 끄고, 그다음에 정교하게 다듬는다'는 순서가 실제로 안전하게 작동한 사례로 볼 수 있습니다.
이 한 틈은 고쳐졌지만, '검증 코드가 있다'와 '그 검증이 우리가 막으려던 질문을 실제로 막는다'는 서로 다른 문장이라는 확인은 다른 플러그인, 다른 프레임워크에서도 계속 나옵니다 — 그래서 저희는 이 커밋 하나가 아니라 이 질문을 남깁니다.
09결론
Elementor 온보딩 모듈의 admin_init 관문이 nonce 검증만 하고 current_user_can() 권한 검사를 하지 않은 것이 근본원인입니다(W1). 그 nonce 자체가 권한과 무관하게 모든 로그인 사용자에게 배포되고 있었던 것(W2)이 이 결함의 진입장벽을 최하위 권한 계정 수준까지 낮췄습니다. 두 미흡점이 만나 최하위 권한 Subscriber 계정이 elementor_upload_and_install_pro 액션으로 위조 플러그인을 설치·활성화해 서버에서 임의 PHP 코드를 실행할 수 있었습니다. CVSS 8.8(NVD), CWE-862 + CWE-434이며, 3.6.3 패치는 이 공격 경로를 완전히 닫은 것으로 확인됩니다.
이 CVE의 표준판(요약본)은 아직 별도로 작성되지 않았습니다.
참고 자료
이 글의 코드 발췌(core/app/modules/onboarding/module.php의 Module::__construct()·maybe_handle_ajax()·upload_and_install_pro(), core/common/app.php의 App::init_components(), core/common/modules/ajax/module.php의 NONCE_KEY·create_nonce()·get_init_settings())는 elementor/elementor GitHub 저장소(벤더 본인이 운영하는 공식 배포 미러)의 커밋 e66df28f9c7c65b85e3262f4006821621233b876(v3.6.2 태그, 패치 전)·557eff68475cc9ff8e05880ff00301418902cddc(v3.6.3 태그, 패치 후)·d30e5a5860685f2d48ce7278f0d582624af1abee(v3.6.4 태그, 후속 강화)를 얕은 클론(shallow clone)으로 직접 받아 파일·라인 단위로 대조했습니다. NVD가 1차 패치 근거로 인용하는 WordPress.org 플러그인 SVN 체인지셋(2708766)은 봇 차단 챌린지(HTTP 403)로 직접 열람하지 못했으나, elementor/elementor GitHub 태그 간 diff는 동일한 버전 범프(3.6.2→3.6.3)를 반영한 벤더 자체 배포본이므로 이 한계를 안고 코드 사실을 기술했습니다. CVSS·CWE·영향 버전·공개일은 NVD API(services.nvd.nist.gov)에서 직접 조회했습니다. 근본원인(W1·W2) 자체는 Wordfence의 서술에 의존하지 않고 Elementor 자체 오픈소스(위 커밋들)를 직접 읽어 저희가 독립적으로 재구성·확증한 것입니다 — core/common/app.php의 Ajax 모듈 무조건 로드 vs Finder 모듈 조건부 로드 대비(W2)는 저희가 코드를 직접 대조해 처음 짚어낸 지점으로, Wordfence 블로그가 명시적으로 언급한 부분이 아닙니다. 반면 Wordfence 블로그·자사 threat-intel 페이지 원문은 봇 차단(자동화 접근 차단)으로 저희가 직접 열람하지 못했습니다 — 그 사이트가 서술한다고 알려진 내용(nonce가 모든 인증 사용자에게 노출된다는 설명, 발견자 이름, 자체 CVSS 9.9 산정)은 여러 검색엔진 결과·2차 집계 사이트(SentinelOne 등)의 교차 인용으로만 확인했으며, 원문 byte-level 대조는 하지 못했습니다 — 그중 CVSS 9.9 수치는 이 한계 때문에 §CVSS 절에서 미검증으로 명시하고 본문에서는 NVD 확인값(8.8)만 공식값으로 씁니다. 실제 공격에 쓰이는 zip 파일 구조(elementor-pro 폴더명·플러그인 헤더 요건)는 공개 PoC(exploit-db #50882)에 대한 설명을 Elementor 소스코드(upload_and_install_pro())와 교차 대조한 것이며, 저희가 그 PoC를 직접 실행해 재현하지는 않았습니다 — 이 한계는 §패치 완전성 평가·본문 배지에도 명시했습니다.
- Wordfence — "Critical Remote Code Execution Vulnerability in Elementor" · 이 글이 재구성한 원 발견자(Ramuel Gall)의 분석(봇 차단으로 저희가 원문을 직접 열람하지는 못했고, 2차 인용으로 교차확인)
- NVD — CVE-2022-1329 상세 · CVSS 8.8, CWE-862/CWE-434, 영향 버전 3.6.0~3.6.2, 공개일 2022-04-19
- Elementor 오픈소스 — 패치 전 module.php(v3.6.2 태그) · W1 코드 근거
- Elementor 오픈소스 — 패치 후 module.php(v3.6.3 태그) · 패치 diff 근거
- Elementor 오픈소스 — core/common/app.php(v3.6.2 태그) · W2 코드 근거(Ajax 무조건 로드 vs Finder 조건부 로드)
- Elementor 오픈소스 — module.php(v3.6.4 태그) · §패치 완전성 Q2 근거(세분화 capability로 후속 강화)
- Exploit-DB #50882 — WordPress Plugin Elementor 3.6.2 RCE (Authenticated) PoC · 공격 흐름(액션명·zip 구조) 교차 확인 근거, 저희가 직접 실행하지는 않음
- Plugin Vulnerabilities — 독립 병행 공개 (2022-04-12)
- Patchstack — 패치 타임라인·3.6.4 후속 강화 정황
- infiltr8 Lab, 「CVE-2024-23897 (Jenkins CLI 임의 파일 읽기) 분석」 — 같은 계열(신뢰 경계가 어긋난 검증) 논평 연결
- infiltr8 Lab, 「CVE-2026-5430 (WSO2 API Manager JWT 서명검증 우회) 분석」 — 같은 계열(검증 존재≠검증 유효) 논평 연결