Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-66421-OpenClaw-Dashboard-Stored-XSS-via-lastMessage-Session-Field — 보안 권고: 에이전트 메시지를 통한 저장형 크로스 사이트 스크립팅으로 인한 세션 토큰 탈취 (openclaw-dashboard) | Kitploit
도구/GitHubGitHub/theopaid/cve-2026-66421-openclaw-dashboard-stored-xss-via-lastmessage-session-field
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityAPI SecurityAI Security
GitHubtheopaid/cve-2026-66421-openclaw-dashboard-stored-xss-via-lastmessage-session-field

CVE-2026-66421-OpenClaw-Dashboard-Stored-XSS-via-lastMessage-Session-Field

보안 권고: 에이전트 메시지를 통한 저장형 크로스 사이트 스크립팅으로 인한 세션 토큰 탈취 (openclaw-dashboard)

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
저장소 보기
18일 전아직 검토되지 않음

보안 권고: 에이전트 메시지를 통한 저장형 크로스 사이트 스크립팅으로 인한 세션 토큰 탈취 (openclaw-dashboard)

제목: OpenClaw Dashboard의 lastMessage 세션 필드를 통한 저장형 XSS CVE ID: CVE-2026-66421

https://github.com/tugcantopaloglu/openclaw-dashboard

요약

대시보드 랜딩 페이지의 세션 테이블에는 각 에이전트 세션의 마지막 메시지가 표시됩니다. 해당 텍스트는 에이전트의 대화 기록에서 가져와 이스케이프 없이 innerHTML로 페이지에 작성됩니다. OpenClaw는 다중 채널 에이전트 게이트웨이이므로, 메시지 텍스트는 채팅 그룹이나 웹훅처럼 에이전트와 대화할 수 있는 모든 사람에게서 올 수 있습니다. HTML 페이로드를 포함한 메시지는 관리자가 대시보드를 여는 즉시 관리자 브라우저에서 스크립트로 실행됩니다.

  • CWE-79: 웹 페이지 생성 중 입력의 부적절한 중화 (크로스 사이트 스크립팅)
  • CVSS 4.0: 8.8 (높음). 벡터: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N

영향을 받는 버전

최초 공개 릴리스부터 존재합니다. 취약한 렌더링 코드는 가장 이른 태그(v1.1.0)와 현재 main(d6198d0)까지의 모든 이후 커밋에 존재합니다. 작성 시점 기준으로 아직 수정되지 않았습니다.

위협 모델

공격자는 에이전트의 세션 대화 기록에 도달하는 메시지를 보낼 수 있는 주체입니다. 대시보드 계정은 필요하지 않습니다. 일반적인 OpenClaw 배포 환경에서 여기에는 연결된 채팅 채널의 구성원과 웹훅을 통해 에이전트에 도달하는 모든 소스가 포함되므로, 공격자는 종종 운영자의 신뢰 경계 밖에 있습니다.

페이로드는 대화 기록에 저장되며 관리자가 세션 페이지를 볼 때마다 렌더링됩니다. 이 페이지는 기본 랜딩 화면이며 타이머로 새로고침되므로, 관리자가 평소 사용하는 대시보드를 로드하는 것만이 필요한 유일한 상호작용입니다. AT:P는 공격자가 의존하는 단 하나의 조건, 즉 배포 환경이 공격자의 메시지를 대시보드가 표시하는 세션으로 라우팅한다는 점을 반영합니다.

근본 원인

1단계. 메시지 텍스트가 대화 기록에서 추출됩니다. 서버는 가장 최근 메시지를 읽고 해당 텍스트를 80자로 자른 뒤, 샌니타이즈 없이 반환합니다:

root@kitploit:~
// server.js:474-481
if (typeof msg.content === 'string') {
  text = msg.content;
} else if (Array.isArray(msg.content)) {
  for (const b of msg.content) {
    if (b.type === 'text' && b.text) { text = b.text; break; }
  }
}
if (text) return text.replace(/\n/g, ' ').substring(0, 80);

2단계. 세션 API를 통해 노출됩니다. getSessionsJson은 각 세션의 lastMessage 필드에 해당 텍스트를 넣습니다:

root@kitploit:~
// server.js:538
lastMessage: getLastMessage(s.sessionId || key),

GET /api/sessions는 이 배열을 브라우저에 반환합니다.

3단계. 이스케이프 없이 DOM에 작성됩니다. 세션 테이블은 문자열 연결로 각 행을 구성하고 innerHTML로 할당합니다:

root@kitploit:~
// index.html:3758
const lastMsg = s.lastMessage ? s.lastMessage.substring(0, 60) + (s.lastMessage.length > 60 ? '…' : '') : '';
root@kitploit:~
// index.html:3773
<div class="table-cell" style="..." onclick="toggleSessionExpand('${escapedKey}', event)">${lastMsg}</div>

lastMsg는 HTML 문자열에 그대로 삽입됩니다. 이 경로에는 어떤 인코딩 단계도 없습니다.

같은 테이블은 s.label(index.html:3770)과 s.key(index.html:3767)도 동일한 방식으로 행 마크업에 삽입합니다. 이 필드에는 60자 제한이 없으므로, 이들 값을 조작할 수 있는 공격자에게 페이로드를 넣을 더 많은 공간을 제공합니다.

server.js:298의 Content-Security-Policy는 인라인 이벤트 핸들러를 허용하므로(script-src 'self' 'unsafe-inline'), onerror 핸들러가 실행됩니다.

개념 증명

  1. 에이전트에게 메시지를 보낼 수 있는 주체로서, 60자 제한에 맞는 짧은 페이로드를 텍스트로 한 메시지를 보냅니다. 예를 들어:

    root@kitploit:~

    이 페이로드는 56자이며 일반 메시지처럼 에이전트의 세션 대화 기록에 도달합니다.

  2. 서버가 페이로드를 이스케이프되지 않은 채 그대로 반환하는지 확인합니다:

    root@kitploit:~
    curl -H "Authorization: Bearer ADMIN_TOKEN" http://TARGET:7000/api/sessions
    

    영향을 받는 세션의 lastMessage 필드에는 이스케이프되지 않은 원본 `` 문자열이 포함됩니다.

  3. 관리자가 대시보드를 엽니다. 세션 페이지가 기본 화면이므로 추가 탐색이 필요 없습니다. 행이 렌더링되고 브라우저가 `` 태그를 파싱하면 onerror 핸들러가 실행되어, 관리자의 세션 토큰이 페이로드에 의해 읽힙니다.

console.log 본문을 동일 출처의 인증된 엔드포인트에 대한 fetch로 바꾸면, 페이로드는 로그인한 사용자의 권한으로 동작할 수 있습니다.

영향

로그인한 사용자 권한으로 대시보드 출처(origin)에서 스크립트가 실행되며, 에이전트에게 메시지를 보내기만 하면 되는 공격자도 이에 도달할 수 있습니다. 페이로드는 세션 토큰을 읽고, 에이전트 자체의 지시 파일과 OpenClaw 구성을 편집하는 엔드포인트를 포함한 인증된 엔드포인트를 호출할 수 있습니다. 기본 페이지에서 실행되므로, 관리자가 특별한 조치를 취할 필요가 없습니다.

수정 방안

  • 행 마크업에 삽입하기 전에 lastMessage, label, key를 HTML 인코딩하거나, HTML 문자열 대신 textContent로 셀을 구성합니다.
  • innerHTML로 렌더링되는 다른 세션 필드에도 동일한 인코딩을 적용합니다.
  • script-src에서 'unsafe-inline'을 제거하여 인코딩 단계를 놓치더라도 주입된 마크업이 실행되지 않도록 합니다.
도구 다운로드