기술 분석 · Apache DolphinScheduler
워크플로 일괄 복사·이동의 프로젝트 간 권한 검사 우회
CVE-2026-71897에서 확인된 워크플로 일괄 작업의 프로젝트 권한 경계와 Apache DolphinScheduler의 공개된 수정 권고를 분석합니다.
워크플로 작업 권한이 프로젝트 경계를 넘을 때
인증된 DolphinScheduler 사용자가 필요한 권한이 없는 프로젝트의 워크플로를 복사하거나 이동할 수 있었습니다. Apache는 2026년 9월 29일 이 인가 오류를 CVE-2026-71897로 공개했습니다. 기존 계정으로 수행하는 워크플로 작업의 권한 범위가 문제였으며, 세션 탈취나 인증되지 않은 접근에 관한 취약점은 아닙니다. Apache 권고문.
제가 살펴본 질문은 일괄 작업이 영향을 주는 모든 워크플로에 프로젝트 경계를 유지하는지였습니다. 보호된 프로젝트를 가진 Alice와, 별도 프로젝트에서 정당한 워크플로 권한을 가진 일반 사용자 Mallory를 생각해 보겠습니다. Mallory의 프로젝트에서 작업할 권한이 Alice의 워크플로에 대한 권한까지 부여해서는 안 됩니다. 당시 조사에서는 대상 워크플로를 식별할 수 있다고 가정했으며, 보호된 워크플로를 독립적으로 찾아내는 방법까지 입증하지는 않았습니다.
애플리케이션 관찰은 직접 빌드한 DolphinScheduler 3.4.2의 로컬 독립 실행형 Docker 환경에서 얻었고, 데이터베이스는 인메모리 H2를 사용했습니다. 앞선 서비스 수준 검사는 배포된 3.4.2 패키지가 아닌 개발 스냅샷을 사용했습니다. 이 글을 위해 당시 보존한 애플리케이션 기록과 공개 소스를 검토했으며, 취약점을 새로 재현하거나 수정 릴리스를 시험하지는 않았습니다.
프로젝트 권한 검사를 실제 워크플로까지 연결하기
3.4.2에 이미 존재하는 프로젝트 인가 보조 함수는 방어 방식의 기준을 보여줍니다. dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectServiceImpl.java의 checkProjectAndAuthThrowException은 전달받은 프로젝트에 대해 사용자에게 요청된 권한이 있는지 검사합니다.
if (!canOperatorPermissions(loginUser, new Object[]{project.getId()}, AuthorizationType.PROJECTS, permission)) {
throw new ServiceException(Status.USER_NO_OPERATION_PROJECT_PERM, loginUser.getUserName(),
project.getCode());
}
이는 수정 패치가 아니라 3.4.2의 기존 인가 코드입니다. 보조 함수의 주변 코드는 프로젝트가 없는 경우도 거부합니다. 이 함수는 해당 프로젝트에 대한 권한을 판단하지만, 이후 작업에 포함된 모든 워크플로가 어느 프로젝트에 속하는지까지 그 자체로 확인하지는 않습니다.
이 구별이 이번 취약점에서 필요한 방어 요건입니다. 일괄 작업은 프로젝트에 대한 권한을 실제로 복사하거나 이동하는 리소스와 연결해야 합니다. 영향을 받는 워크플로가 허가된 원본 프로젝트 밖에 있다면, 허가된 원본과 대상 프로젝트에 각각 유효한 권한이 있다는 사실만으로는 충분하지 않습니다. 상태를 바꾸기 전에 권한 판단과 리소스의 프로젝트 관계가 모두 맞아야 합니다.
위 코드는 전체 취약 호출 경로가 아니라 권한 모델을 설명합니다. Apache의 공개 평가는 그 결과로 발생한 실패를 확인합니다. 일괄 복사와 이동이 호출자의 권한 밖에 있는 프로젝트의 워크플로에도 영향을 줄 수 있었습니다.
성공 메시지 대신 실제 상태를 확인하기
성공 응답만으로는 허가되지 않은 복사나 이동이 입증되지 않습니다. 당시 로컬 조사에서는 일반적인 프로젝트 범위의 동작과 일괄 작업 이후 애플리케이션에서 확인되는 상태를 비교했습니다.
| 과거 검증의 비교 조건 | 기록된 관찰 | 뒷받침하는 내용 |
|---|---|---|
| 일반적인 프로젝트 범위의 워크플로 조회 | 다른 프로젝트의 워크플로가 반환되지 않았습니다. | 호출자의 프로젝트 맥락에서는 해당 워크플로에 일반적으로 접근할 수 없었습니다. |
| 일괄 복사 이후 대상 프로젝트 확인 | 호출자가 제어하는 대상 프로젝트에 복사본이 나타났습니다. | 성공 메시지만 반환된 것이 아니라 프로젝트를 넘는 결과가 만들어졌습니다. |
| 일괄 이동 이후 프로젝트 확인 | 워크플로가 대상 프로젝트에 나타났고 원래 프로젝트에서는 더 이상 조회되지 않았습니다. | 워크플로의 프로젝트 연결이 바뀌었습니다. |
이는 보존된 애플리케이션 응답을 요약한 것이며 재현 절차가 아닙니다. 작업 이후의 상태는 HTTP로 관찰했으며, 데이터베이스 행의 변경 전후를 별도로 수집한 것은 아닙니다. 이 구분을 통해 결론을 애플리케이션에서 실제로 드러난 범위에 한정합니다.
검토할 만한 다른 설명은 일괄 작업에 의도적으로 더 넓은 프로젝트 권한이 부여된다는 것이었습니다. 조회 동작과의 차이는 유용했지만, 그것만으로 의도된 정책까지 확정할 수는 없었습니다. Apache의 공개된 CVE 기록은 권한 없는 프로젝트에 대한 작업을 잘못된 인가로 분류하며, 의도된 경계를 확인해 줍니다.
확인된 결과와 한계
근거가 뒷받침하는 결과는 인증된 사용자가 프로젝트 경계를 넘어 허가되지 않은 워크플로 복사나 이동을 수행할 수 있다는 것입니다. 관리자 접근, 세션 탈취, 코드 실행이나 다양한 운영 환경의 동작까지 입증한 것은 아닙니다. 로컬 구성만으로 관련 워크플로 권한이 실제 배포 환경에서 얼마나 흔하게 부여되는지도 알 수 없습니다.
Apache는 수치 점수 없이 Moderate로 평가했고, CISA-ADP는 Medium 4.3 (CVSS 3.1)을 부여했습니다. 이는 공개된 CVE 데이터에 기록된 출처가 다른 평가이며, 이 글에서 새로 산정한 심각도가 아닙니다.
상태 변경 전에 프로젝트 소속과 권한을 확인하기
Apache는 3.4.3 이전 버전이 영향받는다고 밝히고 수정 릴리스인 3.4.3으로 업그레이드할 것을 권고합니다. 이는 벤더의 공개된 수정 권고입니다. 이 글의 릴리스별 로컬 근거는 3.4.2에 관한 것이며, 문제를 도입한 변경이나 최초 영향 릴리스를 독립적으로 확정하지 않습니다. 검증된 수정 차이나 수정 릴리스의 실행 결과를 제시하는 글도 아닙니다.
방어에 필요한 것은 복사나 이동 전에 실제 워크플로의 프로젝트를 확인하고, 호출자에게 적용되는 원본 및 대상 프로젝트 권한을 검사하는 일입니다. 영향을 받는 모든 워크플로가 이 요건을 충족해야 하며, 허가된 항목 하나가 무관한 다른 항목에 대한 권한까지 부여해서는 안 됩니다.
다음은 제안하는 회귀 검사이며, 실행 결과나 업스트림 테스트 범위에 대한 설명이 아닙니다.
| 제안하는 사례 | 필요한 동작 |
|---|---|
| 모든 워크플로와 양쪽 프로젝트 권한이 허가됨 | 정상적인 일괄 복사와 이동이 유지돼야 합니다. |
| 워크플로가 허가된 원본 프로젝트 밖에 있음 | 허가되지 않은 작업을 거부하고 해당 워크플로를 바꾸지 않아야 합니다. |
| 호출자에게 필요한 대상 프로젝트 권한이 없음 | 보호된 상태를 복사하거나 이동하기 전에 작업을 거부해야 합니다. |
| 허가된 워크플로와 허가되지 않은 워크플로가 한 일괄 작업에 포함됨 | 모든 항목에 인가 검사를 적용하고 권한이 없는 워크플로는 변경하지 않아야 합니다. |