CVE-2026-89274 (WP Recipe Maker 임의 숏코드 실행) 분석

분류: CVE · 웹·서버 · 코드 인젝션 · CVE-2026-89274 · [표준]

방문자가 남긴 별점 후기 한 줄이, 레시피 페이지가 다시 그려질 때마다 서버에서 숏코드로 실행됩니다. WordPress 요리 플러그인 WP Recipe Maker가 후기 본문을 구조화 데이터에 넣기 전에 숏코드를 “지우는” 대신 “실행”하면서 벌어진 일입니다. 계정도 필요 없고, 후기가 한 번 승인되기만 하면 그 뒤로는 모든 방문자에게 자동으로 트리거됩니다.

이런 버그의 상당수는 “정화(sanitize)“라는 이름의 함수가 실제로는 입력을 먼저 실행하고 나서 지우는, 순서가 뒤집힌 처리에서 옵니다. 살균제를 뿌리기 전에 이미 반응이 끝나 있는 셈입니다. 이 글은 그 순서 역전이 어떻게 무인증 코드 인젝션으로 번지는지, 그리고 왜 “신뢰할 수 없는 데이터”가 하필 SEO용 메타데이터 경로로 새어 들어왔는지를 봅니다.

개요

WP Recipe Maker는 WordPress에서 레시피 카드와 구조화 데이터(JSON-LD)를 만들어 주는 플러그인입니다. CVE-2026-89274는 이 플러그인이 레시피 메타데이터를 정리하는 과정에서 방문자가 통제하는 문자열에 대해 WordPress의 do_shortcode()를 호출해, 사이트에 등록된 임의의 숏코드가 서버 측에서 실행되는 결함입니다.

  • 영향 버전: 10.8.1 이하 전체 (10.8.2에서 수정) — ⚠️미확인(팩트체크 대상, NVD·Wordfence advisory 대조 필요)
  • 취약점 유형: CWE-94, 코드 생성의 부적절한 제어(코드 인젝션) — ⚠️미확인
  • 심각도: CVSS 3.1 기준 9.1(Critical), 벡터 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N — ⚠️미확인
  • 인증 요구: 없음(무인증). 단, 주입된 후기 댓글이 승인을 통과해야 실행됩니다 — ⚠️미확인
  • 할당 CNA: Wordfence. CVE 레코드 공개일(datePublished) 2026-09-19, Wordfence advisory 자체 공개일(“Publicly Published”)은 2026-09-18로 표시됨 — ⚠️미확인(두 날짜 구분 필요, 1차출처 대조)

여기서 선을 하나 분명히 그어 둡니다. 이 결함은 임의 시스템 명령 실행(RCE)이 아니라, 이미 그 사이트에 등록되어 있는 WordPress 숏코드를 실행시키는 것입니다. 무엇이 얼마나 위험한지는 사이트가 어떤 숏코드를 물고 있느냐에 달려 있습니다.

기술 배경

숏코드(shortcode)는 WordPress에서 [대괄호] 토큰을 실제 출력으로 바꿔 주는 기능입니다. 예를 들어 게시물 본문에 [갤러리]를 적으면 WordPress가 그 자리에 이미지 갤러리를 그려 줍니다. 확장 플러그인들은 저마다 숏코드를 등록하며, 그중에는 첨부파일·게시물 필드·설정값을 꺼내 보여 주는 것도 있습니다.

숏코드를 실제로 펼치는 함수가 do_shortcode()이고, 반대로 토큰을 실행하지 않고 그냥 지우는 함수가 strip_shortcodes()입니다. 신뢰할 수 없는 문자열에는 실행이 아니라 제거가 정답입니다.

또 하나의 배경은 JSON-LD 구조화 데이터입니다. 레시피 플러그인은 검색엔진이 별점·조리시간·후기를 이해하도록 페이지에 기계용 메타데이터를 심습니다. 이때 후기 별점 댓글의 본문이 reviewBody 필드로 그대로 복사됩니다. 즉 방문자 입력이 “메타데이터”라는 이름을 달고 신뢰 경로로 들어오는 구조입니다.

CVE 분석 요약

문제의 지점은 메타데이터를 정리하는 함수 WPRM_Metadata::sanitize_metadata()입니다(includes/public/class-wprm-metadata.php). 이 함수는 메타데이터 배열을 재귀적으로 훑다가, 말단의 스칼라 값 하나하나에 대해 정화를 수행합니다. 그런데 그 정화가 아래 순서로 이뤄집니다.

정화값 = strip_shortcodes( wp_strip_all_tags( do_shortcode( 입력 ) ) )
                                              └── 가장 안쪽에서 먼저 실행됨

개념용 단순화 — 실제 페이로드/원본 코드 아님. 호출 중첩 순서만 보여주기 위한 도식.

핵심은 호출 순서입니다. 가장 안쪽 do_shortcode()가 먼저 실행되어 입력 안의 숏코드 토큰을 펼쳐 버립니다. 그 결과물이 바깥쪽 strip_shortcodes()로 넘어가지만, 이 바깥 함수는 이미 실행되고 남은 잔여 토큰만 지울 뿐, 이미 만들어진 출력은 되돌리지 못합니다. “지우기”가 “실행하기” 뒤에 오면 지우기는 무의미해집니다.

데이터가 흘러 들어오는 경로는 이렇습니다.

  1. 공격자가 레시피에 별점 후기 댓글(wprm-comment-rating)을 남기고, 그 본문에 숏코드 토큰을 넣습니다.
  2. 댓글 본문(comment_content)이 레시피의 구조화 데이터 reviewBody 필드로 복사됩니다.
  3. 그 필드가 페이지를 그릴 때마다 sanitize_metadata()를 거치고, 위 순서 역전 때문에 숏코드가 서버에서 실행됩니다.
  4. 실행 결과가 JSON-LD에 박혀 모든 방문자에게 전달됩니다.

전제 조건이 하나 있습니다. 별점 후기 댓글은 워드프레스 댓글 승인을 통과해야 실제로 렌더 경로에 올라옵니다 — ⚠️미확인. 사이트가 첫 댓글 자동승인을 켜 두었거나, 공격자가 한 번 승인된 이력이 있는 방문자이거나, 관리자가 무심코 승인하면 그 시점부터 트리거됩니다. 이 승인 조건 때문에 “완전 무전제 원클릭”보다는 한 단계 문턱이 있지만, 사이트 설정(첫 댓글 자동승인 등)에 따라 낮은 문턱이 될 수 있습니다.

패치 방향(10.8.2): 벤더는 이 자리에서 do_shortcode() 호출을 실행하지 않는 방식으로 교체한 것으로 보입니다. 공개 변경 로그의 항목 취지는 “레시피 메타데이터에서 후기 텍스트의 숏코드 실행을 막는다(Prevent shortcode execution of comment text in the recipe metadata)“로 확인됩니다. 다만 교체된 내부 함수명·구현 세부(일부 자료가 인용하는 WPRM_Instacart::do_shortcode_safe() 등)는 공개 검색·공식 레코드만으로는 검증되지 않았습니다 — ⚠️미확인(SVN diff 원문 대조 필요, 확인 전 함수명 단정 금지). 정리하면 방문자 통제 메타데이터를 서버에서 절대 펼치지 않도록 순서 문제 자체를 없앤 수정입니다.

⚠️ 인용 코드의 정확한 파일 라인 번호는 자료 간 불일치가 있습니다(한 직접 판독은 878행 부근, 집계 사이트는 181/553/1028행을 인용). 발행 전 고정 SVN 태그 원문으로 재확인이 필요하며, 이 초안은 라인 번호를 단정하지 않았습니다.

공격 시나리오 · 영향도 + 대응방안

공격 시나리오(개념): 후기 댓글에 숏코드 토큰을 심는다 → 댓글이 승인된다 → 레시피 페이지가 렌더될 때 서버가 그 숏코드를 실행한다 → 실행 결과가 구조화 데이터에 실려 노출된다. (작동하는 완성형 페이로드는 이 글에 싣지 않습니다 — 개념까지만.)

영향도: 실행되는 것은 그 사이트에 이미 등록된 숏코드에 한정됩니다. 위험의 크기는 설치된 플러그인이 어떤 숏코드를 제공하느냐로 결정됩니다. 첨부파일·게시물 필드·비공개 값을 출력하는 숏코드가 있다면 그 내용이 reviewBody를 통해 노출될 수 있습니다. CVSS 벡터가 기밀성뿐 아니라 무결성도 높음(I:H)으로 매긴 것은, 공격자 통제 콘텐츠가 렌더된 페이지 출력을 바꾸기 때문으로 보입니다 — 이 부분은 사실(벡터)과 해석(왜 I:H인가)을 나눠서 읽어야 합니다. 다시 강조하면 RCE는 아닙니다.

대응방안

  1. 근본 — 안전 버전으로 업데이트: WP Recipe Maker를 10.8.2 이상으로 올립니다(2026-09-17 공개) — ⚠️미확인(벤더 변경 로그·NVD 재확인). 이것이 순서 역전 자체를 없애는 유일한 근본 처방입니다.
  2. 차선(즉시 업데이트가 어려울 때):
    • 댓글 승인 문턱을 높입니다. 첫 댓글 자동승인을 끄고, 별점 후기의 자동 게시를 막아 신뢰 경로 진입 자체를 차단합니다.
    • 레시피에 별점 후기 기능이 필수가 아니라면 일시 비활성화해 reviewBody 유입 경로를 닫습니다.
    • 웹 방화벽(WAF)에서 댓글 본문의 숏코드 토큰 패턴을 차단 규칙으로 거르는 방법도 일반적 완화책으로 고려할 수 있습니다(1차출처가 직접 권고한 대응은 아님). 우회 여지가 있어 근본 처방은 아닙니다.
  3. 탐지 관점: 승인 대기·승인된 별점 후기 댓글 본문에 [ 숏코드 토큰이 섞여 있는지, 그리고 레시피 페이지의 JSON-LD reviewBody에 기대와 다른 출력(예상치 못한 링크·경로·내부 값)이 실리는지를 점검합니다.

결론

한 줄 요약: “정화” 함수가 신뢰할 수 없는 입력을 지우기 전에 먼저 실행했고, 그 입력이 하필 방문자가 쓰는 후기였습니다.

이 부류가 반복되는 이유는 단순합니다. 개발자가 do_shortcode()를 “출력을 예쁘게 만드는 정규화”로 여기고 정화 파이프라인 안쪽에 끼워 넣기 때문입니다. 실행과 제거의 순서가 뒤집히는 순간, 이름이 아무리 “sanitize”여도 그건 실행기입니다.

이 한 틈은 10.8.2에서 막혔지만, “신뢰할 수 없는 데이터를 정화 도중에 실행한다”는 사고방식은 다른 플러그인·다른 필드에서 또 나타납니다. 그래서 우리는 개별 패치가 아니라 순서를 의심하는 방법을 기록으로 남깁니다.

References / 참고자료

  1. CVE.org, “CVE Record CVE-2026-89274” — CNA(Wordfence)가 발행한 공식 1차 취약점 레코드(영향 버전·심각도·공개일 기준). https://www.cve.org/CVERecord?id=CVE-2026-89274
  2. Wordfence Threat Intelligence, 취약점 advisory — 할당 CNA의 권고 및 CVSS/CWE 근거(1차 CNA 출처). https://www.wordfence.com/threat-intel/vulnerabilities/id/d6ad49ff-85eb-4d05-ba23-51d89695add3?source=cve
  3. NVD, “CVE-2026-89274 Detail” — CVE/CNA 데이터를 집계·보강하는 참고용 레코드(원천 CNA 레코드 아님). https://nvd.nist.gov/vuln/detail/CVE-2026-89274
  4. Bootstrapped Ventures(벤더), “WP Recipe Maker Changelog” — 10.8.2 수정 항목·공개일 근거. https://help.bootstrapped.ventures/article/124-wp-recipe-maker-changelog
  5. WordPress.org Plugin SVN, class-wprm-metadata.php (tag 10.8.1) — 취약 코드 위치의 1차 원본(패치 전). https://plugins.svn.wordpress.org/wp-recipe-maker/tags/10.8.1/includes/public/class-wprm-metadata.php
  6. WordPress.org Plugin SVN, class-wprm-metadata.php (tag 10.8.2) — 패치 후 원본(수정 대조용). https://plugins.svn.wordpress.org/wp-recipe-maker/tags/10.8.2/includes/public/class-wprm-metadata.php
  7. strix.ai, “CVE-2026-89274: WP Recipe Maker Code Injection (CVSS 9.1)” — 근본원인·패치 동작에 대한 독립 분석(교차 재구성 참고). https://www.strix.ai/cve/CVE-2026-89274

이 글은 위 원 분석과 1차출처를 우리 관점에서 다시 쓰고 논평을 더한 초안입니다. 취약 코드는 공개 SVN 원본을 근거로 하되 정확한 라인 번호·패치 도우미 내부 구현은 발행 전 재확인 대상(⚠️미확인)으로 남겨 두었습니다. 완성형 익스플로잇·작동 페이로드는 싣지 않았습니다.