풀이 날짜: 2026-09-14 (사용자 확정). 익스플로잇 성공은 2026-09-16 사용자 확인에 따른다. 아래 실행 결과는 보존된 원본 기록이며 이번 감사에서 새로 실행한 결과가 아니다.

게시글 열람 조건과 관리자 세션

Leakless는 사용자 게시글을 관리자 브라우저 봇이 방문하는 문제다. XSS 입력점만 지적해서는 관리자 결과가 어떻게 관찰됐는지 설명할 수 없다. 게시글 공개 조건, 세션 identity, 봇의 로그인·로그아웃 시점을 각각 분석해야 한다.

/view의 코드상 조건

index.js의 /view가 콘텐츠를 반환하기 전에 적용하는 조건은 다음과 같다. 응답 HTML 등은 생략했다.

if (username in accounts &&
    (username != ADMIN_ID || req.session?.username === ADMIN_ID)) {
    const user = accounts[username];
    if (user.checked && dayjs().isAfter(user.viewtime)) {
        // 콘텐츠 응답
    }
}

콘텐츠는 HTML 템플릿에 삽입되므로 출력 맥락도 중요하다. 하지만 관리자 글에는 세션 identity 조건이 추가되며 예약 공개 상태까지 만족해야 한다. 따라서 일반 계정의 콘텐츠가 실행된 것과 관리자 문맥에서 민감 결과를 읽은 것을 동일하게 취급하지 않는다.

분리해서 추적한 상태

상태 저장 위치·역할 분석에서 확인할 관계
계정 정보 accounts의 password/content/checked/viewtime 계정 변경이 기존 세션에도 반영되는가
로그인 identity session.username 현재 계정 객체와 같은 수명을 갖는가
게시글 공개 checked와 시간 조건 콘텐츠 존재와 열람 가능을 구분
봇 lifecycle 페이지 요청·로그아웃 요청 시작과 서버 처리 완료를 구분

후속 GATES는 Day.js 포맷 처리 시간과 실제 봇 요청 타임라인을 별도 항목으로 검사했다. 함수가 느리다는 관찰만으로 세션 상태가 유지된다고 결론 낼 수 없기 때문에, 다음 페이지 요청에서 관찰된 관리자 identity와 최종 결과를 따로 기록한 것이다.

가설에서 검증으로

초기 REPORT는 정적 분석 시점의 기록이며 최종 solver 부재를 현재 상태로 옮기면 틀린다. GATES는 환경 버전, 상태 변화, 처리 시간, 타임라인, 최종 결과, 독립 실행 조건과 clean restart를 나눠 확인한다. 단순 대기 시간 수치를 영구 상수처럼 소개하지 않고 당시 관찰된 결과로 남긴다.

결과

clean_runs.json의 세 실행은 모두 fresh restart, success=true로 기록되어 있다. 총 소요 시간은 약 25.383초·25.331초·25.149초였으며 로컬 예시 결과를 반환했다. 이것은 solver가 현재 Mac에서도 동작한다는 검증이나 공식 원격 flag 수락이 아니다. 사용자는 익스플로잇 성공을 확인했고, 이번 감사는 기존 파일만 읽었다.

근거 자료

  • sources/Leakless/index.js
  • sources/Leakless/analysis/REPORT.md
  • sources/Leakless/GATES.md
  • sources/Leakless/validation/clean_runs.json

원본 문서·solver·검증 로그는 전달 staging에 보존되어 있다. 이 경로들은 provenance이며 CMS의 다운로드 첨부 링크가 아니다.