1. Ghost CMS (Content Management System)

- 오픈소스 콘텐츠 관리 시스템 [1]

2. 취약점

[사진 1] CVE-2026-26980 [2]

- Content API에서 사용자 입력을 SQL 구문에 직접 삽입하여, 인증되지 않은 공격자가 데이터베이스에서 임의의 데이터를 읽을 수 있는 SQL Injection 취약점 (CVSS: 9.4)

> 해당 취약점과 Click-Fix 공격을 결합하여 웹 사이트의 관리자 API 키를 탈취한 뒤 웹 사이트에 악성 코드를 삽입 [3]

영향받는 버전
- Ghost 3.24.0 ~ 6.19.0 버전

 

- Ghost는 읽기 전용 공개 Content API인 /ghost/api/content/posts/를 제공하며, CONTENT_API_KEY를 사용해 요청을 인증

> CONTENT_API_KEY 값은 테마 HTML에 포함되어 있으므로, 사실상 공개되어 있는 상태

 

- slug-filter-order.js는 slug:[...] 형식의 사용자 입력을 정규표현식으로 추출한 후 쉼표(,)를 기준으로 분할하여 SQL ORDER BY절 내부의 CASE WHEN 구문 생성 [4]

> slug 값에 대한 적절한 검증 또는 매개변수 바인딩 없이 SQL 구문에 직접 포함하여 취약점이 발생

const slugFilterOrder = (table, filter) => {
    let orderMatch = filter.match(/slug:\s?\[(.*)\]/);

    if (orderMatch) {
        let orderSlugs = orderMatch[1].split(',');
        let order = 'CASE ';

        orderSlugs.forEach((slug, index) => {
            order += `WHEN \`${table}\`.\`slug\` = '${slug}' THEN ${index} `;
        });

        order += 'END ASC';

        return order;
    }
};

module.exports = slugFilterOrder;

 

- 만약 요청에 filter=slug:[post-1,post-2,'THEN 0 END ||,|| <INJECTION>||,||CASE WHEN'] 포함되어 있을 경우 CASE WHEN 구문은 다음과 같이 생성됨

CASE
   WHEN `posts`.`slug` = 'post-1' THEN 0
   WHEN `posts`.`slug` = 'post-2' THEN 1
   WHEN `posts`.`slug` = '''THEN 0 END ||' THEN 2  -- 외부 CASE문을 닫고, 문자열 연결(concat)을 시작함
   WHEN `posts`.`slug` = ' || <INJECTION> ||' THEN 3  -- <INJECTION> 구문이 스칼라 표현식으로 실행됨
   WHEN `posts`.`slug` = ' || CASE WHEN'' THEN 4  -- 뒤에 올 END ASC를 흡수하기 위해 새로운 CASE문을 시작함
END ASC

 

- 따라서 공격자가 /ghost/api/content/posts/ 엔드포인트에 Content API Key와 조작된 slug 매개변수를 포함한 요청을 전송해 SQL Injection이 가능

> 이를 통해 데이터베이스 내 관리자 계정 정보, API Key, Session Secret 등의 민감 정보를 추출할 수 있음

[조작된 요청 예시]
GET /ghost/api/content/posts/?key=<CONTENT_API_KEY>&filter=slug:[post-1,post-2,'THEN 0 END ||,|| <INJECTION>||,||CASE WHEN']

3. 대응방안

- 벤더사 제공 업데이트 적용 [5][6][7]

> 매개변수 바인딩을 사용해 사용자 입력이 SQL 구문에 삽입되지 않도록 수정

취약점 제품명 영향받는 버전 해결 버전
CVE-2026-26980 Ghost 3.24.0 ~ 6.19.0 버전 6.19.1

 

- 관리자 비밀번호 및 API 키, 세션 비밀 키 등 모든 비밀 키 변경

- CONTENT_API_KEY 값의 외부 노출 제한

- 탐지 정책 적용 및 모니터링

> slug:[ 또는 slug%3A%5B (URL 인코딩 형식) 뒤에 SQL 키워드(CASE, WHEN, THEN, END, ||, char( , SELECT, randomblob )가 포함된 모든 콘텐츠 API 요청을 차단 또는 경고

4. 참고

[1] https://ghost.org/
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-26980
[3] https://blog.xlab.qianxin.com/ghost-cms-mass-compromised-via-cve-2026-26980-now-fueling-clickfix-attacks/
[4] https://github.com/TryGhost/Ghost/blob/v6.19.0/ghost/core/core/server/api/endpoints/utils/serializers/input/utils/slug-filter-order.js
[5] https://github.com/advisories/GHSA-w52v-v783-gw97
[6] https://github.com/TryGhost/Ghost/commit/30868d632b2252b638bc8a4c8ebf73964592ed91
[7] https://github.com/TryGhost/Ghost/releases/tag/v6.19.1

+ Recent posts