콘텐츠로 이동

Keycloak 비밀번호 재설정 흐름의 계정 탈취 취약점

Keycloak 비밀번호 재설정 흐름의 계정 탈취 취약점 thumbnail
CVE-2026-18963은 Keycloak의 비밀번호 재설정 흐름에서 실행 상태와 작업 토큰 검증이 미흡해 발생한 계정 탈취 취약점이다. 인증되지 않은 공격자가 이메일 확인 링크를 열지 않고 대상 계정의 새 비밀번호를 설정할 수 있다.

요약

CVE-2026-18963은 Keycloak의 비밀번호 재설정 흐름에서 실행 상태와 작업 토큰 검증이 미흡해 발생한 계정 탈취 취약점이다. 인증되지 않은 공격자가 이메일 확인 링크를 열지 않고 대상 계정의 새 비밀번호를 설정할 수 있다.

Keycloak은 2026-08-19에 수정 릴리스를 공개했다. Red Hat은 심각도를 치명적으로 평가하고 CVSS 3.1 점수 9.1을 부여했다. CERT-FR은 2026-08-25 공개 개념 증명 코드가 존재한다고 밝혔다.

항목 내용
CVE CVE-2026-18963
취약 구성 요소 keycloak-services
취약 흐름 reset-credentials
관련 클래스 ResetCredentialEmail, DefaultAuthenticationFlow
공격 조건 원격 접근, 인증 불필요
사용자 상호작용 불필요
취약점 유형 CWE-640, 취약한 비밀번호 복구 절차
공격 결과 대상 계정 비밀번호 변경
Red Hat CVSS 9.1
수정 릴리스 26.4.15, 26.6.6, 26.7.2, 26.8.0

취약 지점

기본 비밀번호 재설정 흐름은 사용자 식별, 재설정 이메일 발송, 이메일 작업 토큰 검증, 새 비밀번호 설정 순서로 진행된다.

reset-credentials 요청
  → 사용자 식별
  → 재설정 이메일 발송
  → 작업 토큰 검증
  → 새 비밀번호 설정

취약한 구현에서는 인증 방식 선택 화면의 상태가 해당 실행 단계의 식별자와 결합되지 않았다. 이전 실행에서 설정된 AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED 상태를 다른 실행 단계에서 다시 사용할 수 있었다.

이 상태로 이메일 실행 단계에 진입하면 ResetCredentialEmail.action()이 현재 사용자와 일치하는 작업 토큰 없이 성공할 수 있었다. 그 결과 흐름이 이메일 링크 검증을 거치지 않고 비밀번호 설정 단계로 넘어갔다.

사용자 식별과 재설정 이메일 발송
  → 인증 방식 선택 상태 재사용
  → reset-credential-email 실행 단계 재진입
  → ResetCredentialEmail.action() 성공
  → 작업 토큰 검증 없이 새 비밀번호 설정

수정된 DefaultAuthenticationFlow는 인증 방식 선택 상태에 현재 AuthenticationExecutionModel 식별자를 저장한다. 다음 요청에서는 저장된 식별자와 현재 실행 식별자가 정확히 일치할 때만 해당 상태를 인정한다.

ResetCredentialEmail에도 작업 토큰의 사용자 식별자를 검사하는 조건이 추가됐다. 토큰에 담긴 사용자와 인증 세션의 현재 사용자가 일치해야 이메일 실행 단계를 완료한다. 회귀 시험은 오래된 재설정 흐름 상태로 이메일 단계를 다시 호출하는 경우를 다룬다.

영향

공격자가 대상 사용자의 식별자를 알면 새 비밀번호를 설정하고 해당 계정으로 인증할 수 있다. 관리자 계정이 탈취되면 그 계정에 이미 부여된 영역, 클라이언트, 역할 및 사용자 관리 권한이 사용될 수 있다.

취약 흐름에서도 실제 재설정 이메일이 발송되고 SEND_RESET_PASSWORD 이벤트가 남는다. 이메일 발송 기록만으로 정상 재설정과 우회를 구분할 수 없다.

인증 경계 우회

이메일 작업 토큰은 재설정 요청과 계정 소유자를 연결한다. 이 취약점은 해당 토큰과 현재 사용자의 일치 여부를 확인하지 않은 채 새 비밀번호 설정 단계에 도달하게 한다.

탐지 포인트

네트워크

이메일 링크를 사용한 정상 재설정에서는 작업 토큰 처리 요청이 나타난다.

GET /realms/<realm>/login-actions/action-token?key=...

재설정 이메일 발송 후 비밀번호가 변경됐지만 해당 요청이 없다면 우회 여부를 조사한다. 링크 검사 제품이 URL을 자동으로 열 수 있으므로 요청 방식, 출발지 주소, 사용자 에이전트와 이후 비밀번호 변경 요청을 함께 비교한다. HEAD 요청만으로 작업 토큰이 정상 처리됐다고 판단하지 않는다.

Keycloak 이벤트

성공한 비밀번호 변경은 RESET_PASSWORD 대신 UPDATE_PASSWORD 또는 UPDATE_CREDENTIAL로 기록될 수 있다. SEND_RESET_PASSWORD와 완료 이벤트는 이벤트 상세 정보의 code_id로 연결한다.

SELECT
  event_time,
  realm_id,
  user_id,
  session_id,
  source_ip,
  event_type,
  code_id
FROM keycloak_events
WHERE event_type IN (
  'SEND_RESET_PASSWORD',
  'UPDATE_PASSWORD',
  'UPDATE_CREDENTIAL',
  'LOGIN'
)
ORDER BY user_id, event_time;

동일한 code_id에서 이메일 발송과 자격 증명 변경이 이어지는 배열은 우회와 정상적인 동일 브라우저 재설정에서 모두 발생할 수 있다. 짧은 처리 시간도 단독 침해 지표로 사용할 수 없다.

취약한 ResetCredentialEmail.action()은 실행 과정에서 사용자의 email_verified 값을 참으로 바꾼다. 다음 조건이 함께 나타나는 계정을 우선 조사한다.

  • 노출 기간에 새 비밀번호 자격 증명이 생성됨
  • 같은 기간에 이메일 확인 상태가 참으로 변경됨
  • VERIFY_EMAIL 또는 UPDATE_EMAIL 이벤트가 없음
  • 관리자 인터페이스를 통한 사용자 변경 기록이 없음

이미 이메일 확인을 마친 계정은 이 변화가 나타나지 않는다. 사용자 가져오기처럼 관리자 이벤트를 남기지 않고 확인 상태를 설정하는 경로도 별도로 배제해야 한다.

서버

credential.created_date를 기준으로 노출 기간에 생성된 비밀번호 자격 증명을 추출한다. 정상 재설정, 관리자 변경, 계정 등록 기록과 대조해 변경 원인을 분류한다.

Keycloak 26.x에서는 이벤트 상세 정보가 event_entity.details_json_long_value에 저장될 수 있다. details_json만 조회하면 code_id가 누락될 수 있으므로 두 열을 모두 확인한다.

비밀번호 변경 직후 생성된 세션, 갱신 토큰, 오프라인 토큰도 조사한다. 권한이 높은 계정에서는 같은 시간대와 출발지 주소에서 발생한 영역, 클라이언트, 역할 및 사용자 설정 변경을 추적한다.

대응

배포 중인 릴리스 계열에 맞는 수정 버전으로 갱신한다.

릴리스 계열 수정 버전
26.4 26.4.15
26.6 26.6.6
26.7 26.7.2
26.8 26.8.0

즉시 갱신할 수 없으면 모든 영역에서 비밀번호 찾기 기능을 끈다.

영역 설정
  → 로그인
  → 비밀번호 찾기
  → 끄기

관리 API를 사용하는 환경에서는 영역 설정의 resetPasswordAllowedfalse로 변경한다. 이 설정은 사용자의 자체 비밀번호 복구도 차단하므로 수정 버전 적용 전 임시 통제로 사용한다.

계정 탈취 흔적이 발견되면 신뢰할 수 있는 경로로 비밀번호를 다시 설정한다. 활성 세션, 갱신 토큰, 오프라인 토큰을 폐기하고 변경된 비밀번호로 생성된 세션과 연동 서비스 접근 기록을 조사한다.

참고 자료