컴퓨터 업계에는 오래된 농담이 하나 있다. DOOM은 결국 무엇 위에서든 돌아간다는 것이다. 게임을 칭찬하는 말이 아니라 도전에 가깝다. 1993년에 나온 이 총싸움 게임은 지금까지 현금인출기, 프린터, 임신 테스트기, 계산기, 레고 블록 한 조각, 그리고 맥북의 터치 바에서까지 실행되었다.
2025년 1월, 한 고등학생이 그 목록에 항목 하나를 더 얹었다. DOOM을 PDF 파일 안에서 돌린 것이다.

요약
한 고등학생이 2020년판 Emscripten으로 DOOM을 asm.js로 컴파일한 뒤, 화면의 각 줄마다 양식 필드를 하나씩 배정해 디스플레이로 삼아 PDF 안에서 실행했다. 320×200, 회색 여섯 단계, 프레임당 약 80밀리초. 취약점은 전혀 관여하지 않았다. 사용된 기능은 모두 PDF 명세에 문서화되어 있고, 설계된 그대로 동작한다. 흥미로운 지점이 바로 거기다 — 그리고 문서에 한 번쯤 십 분을 들일 이유도 거기에 있다.
훌륭한 작업이고 아주 좋은 농담이다. 동시에 이 사이트가 거듭 이야기해 왔고 사람들이 믿기 어려워하는 것도 무리가 아닌 한 가지를, 가장 분명하게 보여 주는 사례이기도 하다. PDF는 페이지를 찍은 사진이 아니다. 코드를 실행할 수 있는 그릇이다.
실제로 어떻게 돌아가는가
프로젝트 이름은 doompdf이고, 만든 사람은 ading2210이라는 이름을 쓰는 개발자다. 방식이 묘기 자체보다 흥미로운데, 네 부분으로 나뉜다.
PDF는 JavaScript를 지원한다. 부가 기능이나 플러그인이 아니라 형식 자체의 일부이며, 자체 표준 라이브러리를 갖고 있고 브라우저도 내장 PDF 엔진에서 이를 구현한다. 양식이 입력값을 검사하고 대화형 문서가 클릭에 반응할 수 있도록 존재하는 기능이다. 게임을 염두에 두고 넣은 사람은 아무도 없었다.
DOOM의 소스 코드는 공개되어 있다 — 다만 실제 사정은 이 줄임말보다 더 세밀하다. id Software가 코드를 공개한 것은 1997년 12월 23일이지만, 그 라이선스는 교육 목적의 사용만 허용했고, 공개된 것도 DOS 원본이 아니라 리눅스 이식판의 코드였다. 음향 라이브러리 DMX의 라이선스가 따로였기 때문이다. GPL로 바뀐 것은 거의 두 해 뒤인 1999년 10월 3일이었다. 중요한 것은 이 두 번째 날짜다. DOOM을 ‘읽을 수 있는 것’에서 ‘합법적으로 다시 만들 수 있는 것’으로 바꿔 놓았기 때문이다. 이 게임이 뜻밖의 자리에 계속 나타나는 이유도 여기에 있다.
둘을 이어 준 것은 일부러 낡은 컴파일러였다. ading2210은 Emscripten 1.39.20 — 2020년판 — 을 썼다. WebAssembly가 아니라 asm.js를 내놓기 때문이다. 요즘 Emscripten은 WebAssembly를 만들지만, PDF에는 WebAssembly 실행 환경이 없다. asm.js는 평범한 JavaScript의 제한된 방언이라서 JavaScript가 도는 곳이면 어디서든 돈다. 옛 도구를 꺼내 든 것은 향수가 아니라 유일한 입구였기 때문이다.
남은 것은 화면 출력, 사람들이 소리 내어 웃는 대목이다. PDF에는 캔버스도 프레임버퍼도, 픽셀을 칠할 만한 것이 아무것도 없다. 대신 양식 필드가 있다. 그래서 게임의 320×200 화면은 ASCII 문자로 그려진다 — 화면의 각 줄마다 텍스트 필드 하나씩, 회색 여섯 단계로 — 그리고 그 텍스트를 다시 쓸 수 있는 속도로 갱신된다. 계산하면 프레임당 대략 80밀리초다. 입력도 같은 길로 들어온다. PDF 엔진이 이미 다룰 줄 아는 필드와 버튼을 통해서다. 말 그대로 작성용 양식 안에서 DOOM을 하는 셈이다.
느리게 돌아간다. 단색이다. 그럼에도 완전히 플레이할 수 있고, 바탕이 된 코드와 마찬가지로 GPL v2로 공개되어 있으며, Chromium 계열 브라우저에서 직접 해 볼 수 있다. 빌드는 자기 WAD 파일을 끼워 넣는 것까지 허용한다.
그다음엔 그 안에서 리눅스를 띄웠다
몇 주 뒤 같은 개발자가 linuxpdf를 공개했다. PDF 파일 안에서 온전한 리눅스 커널이 부팅되는 것으로, RISC-V 에뮬레이터 TinyEMU를 같은 asm.js 수법으로 컴파일해 만들었다. 커널이 올라오는 데 30~60초가 걸리는데, 저자는 이를 실제 하드웨어보다 백 배 넘게 느리다고 표현한다. 조작은 PDF 버튼으로 만든 가상 키보드로 한다.
문서 안의 DOOM은 농담이다. 문서 안에서 에뮬레이트된 CPU가 운영체제를 부팅하는 것은 이미 하나의 주장이다. 그 둘 사이 어딘가에서, 이야기는 더 이상 DOOM에 관한 것이 아니게 된다.
웃기지 않은 부분
여기서 잠시 머물러 볼 만한 생각이 있다. doompdf에는 취약점 악용이 하나도 없다. 결함이 발견된 것도, 무언가가 뚫린 것도, 보안 구멍이 관여한 것도 아니다. 이 프로젝트가 쓰는 모든 것은 PDF 명세에 문서화된 의도적 기능이며, 설계된 그대로 동작한다.

다시 말해, PDF가 1993년 총싸움 게임을 실행하게 해 주는 그 능력은 내일 당신이 열어 볼 청구서 안에도 똑같이 들어 있다. 숨어 있지도, 감춰져 있지도 않다. 그저 거기 있고 쓰이지 않을 뿐이다. 대부분의 문서에는 그것을 쓸 이유가 없기 때문이다.
이것이 이 이야기의 정직한 형태이고, 양쪽을 다 벤다. “문서가 코드를 실행할 수 있으니 조심하라”는 논리는, 그 코드가 놓인 세계가 얼마나 좁은지도 인정해야 한다.
PDF 속 스크립트가 할 수 있는 일과 없는 일
doompdf를 다룬 글들이 대개 이 대목에서 흐릿해지므로, 구체적으로 적을 필요가 있다. 답은 전적으로 그 파일을 무엇으로 열었는가에 달려 있고, 흔한 두 경우는 아주 다르다.
| 기능 | 브라우저 뷰어(Chrome, Edge, Firefox) | Adobe Acrobat Reader |
|---|---|---|
| 열리는 순간 스크립트 실행 | 가능 | 가능(끄지 않았다면) |
| 양식 필드 읽기·쓰기 | 가능 | 가능 |
| 쿠키나 브라우저 저장소 읽기 | 불가 | 해당 없음 |
| 둘러싼 HTML 페이지(DOM) 접근 | 불가 | 해당 없음 |
| 네트워크 요청 | 매우 제한적 | 더 넓음 — 추적 픽셀과 NTLM 유출이 살던 자리 |
| 로컬 파일 접근 | 불가 | 제한적이지만 API 표면은 훨씬 넓음 |
| 외부 프로그램이나 첨부 실행 | 불가 | 확인을 거쳐서 — 역사적으로 악성 문서가 지나던 길 |
이 표는 올바른 방향으로 읽어야 한다. 브라우저에서 스크립트가 든 PDF는 작고 심심한 상자 안에서 돈다. 쿠키도, 저장소도, 둘러싼 페이지에 대한 접근도 없다. doompdf가 사건이 아니라 진기한 구경거리인 이유가 바로 그것이고, “DOOM이 PDF에서 돈다”가 PDF를 두려워할 이유가 되지 않는 까닭도 그것이다.
흥미로운 쪽은 데스크톱 리더 열이다. 명세가 서술하는 JavaScript API를 전부 갖추고 있다. 진짜 업무 문서를 다루기 위한 프로그램이기 때문이다. 문서에게 열리는 순간 바깥에 알리라고 시키거나, 리더마다 다르게 굴게 하거나, 함께 들고 온 무언가를 열자고 권하게 할 수 있는 환경이 바로 이곳이다.
따라서 프로그램이 무엇이든 변하지 않는 세 가지가 있고, 그 셋이야말로 몸에 익혀 둘 만하다.
- PDF는 당신이 아무것도 읽기 전에, 열리는 순간 실행되는 지시를 담을 수 있다.
- PDF는 여는 소프트웨어에 따라 다르게 행동할 수 있다. 당신이 보는 파일이 동료가 보는 파일과 같으리라는 보장은 없다.
- PDF는 보여 주는 것보다 많은 것을 담고 다닌다. 첨부, 숨은 레이어, 수정 이력, 그리고 보낼 생각이 전혀 없었던 메타데이터까지.
이 가운데 어느 것도 일상적인 의미에서 PDF를 위험하게 만들지 않는다. 이번 달에도 수십 개를 열 테고 전부 아무 일 없을 것이다. 다만 우리 대부분이 지니고 다니는 인식 — “그냥 문서일 뿐” — 이 가끔 중요해지는 방식으로 틀렸다는 뜻이기는 하다.
거의 아무도 모르는 설정
표준적인 조언은 “PDF 리더에서 JavaScript를 꺼라”이고, 좋은 조언이다. 다만 그것만으로는 불완전하다. 대부분의 사람은 이제 PDF를 PDF 리더로 열지 않는다. 브라우저 탭에서 열고, 브라우저에는 별도의 스위치가 따로 있다.
파이어폭스는 PDF 스크립트를 켠 채로 배포된다. 설정 이름은 about:config의 pdfjs.enableScripting이며, 파이어폭스 87까지는 false였다가 88부터 true가 되었다. 전체 스위치인 javascript.enabled는 여기에 손대지 않는다. PDF 뷰어는 별도의 세계이고 별도의 설정을 쓴다.
크롬과 엣지에는 PDF 스크립트 전용 스위치가 아예 없다. PDF 속 스크립트는 그 파일이 온 사이트의 JavaScript 권한을 따르며, 주소창의 제어에서 사이트별로 끄거나 chrome://settings/content/javascript에서 전체적으로 끌 수 있다 — 후자는 훨씬 무딘 도구다.
Adobe Acrobat Reader에 모두가 떠올리는 그 스위치가 있다. 환경 설정 → JavaScript → Acrobat JavaScript 사용. 체크를 풀 만한 것은 이 항목이다. Acrobat이 바로 API가 큰 리더이고, 평범한 업무에서 스크립트가 든 PDF를 일부러 쓰는 사람은 거의 없기 때문이다.
실무적으로는 이렇다. Acrobat에서 끄고 브라우저는 그대로 두는 것은 합리적이고 균형 잡힌 선택이다. Acrobat에서만 껐으면서 모든 곳에서 껐다고 믿는 것은 그렇지 않다.
이 정보로 무엇을 할 것인가
실제로 할 일은 적고, 그 십 분의 값어치는 한다.
데스크톱 리더에서 JavaScript를 끈다. Acrobat Reader에서는 환경 설정 → JavaScript. 위험의 한 범주가 통째로 사라지고, 대가는 — 인정하건대 — 양식 필드에서 DOOM을 할 수 없게 되는 것뿐이다.
리더를 최신으로 유지한다. 스크립트는 들어오는 길 하나다. 글꼴과 이미지를 해석하는 코드의 결함은 또 다른 길이고, 업데이트가 고치는 것이 바로 그쪽이다. 역사적으로는 오히려 그쪽이 더 흔한 길이었다.
예상하지 못한 문서는 예상하지 못한 것으로 대한다. 한 번도 물건을 산 적 없는 회사에서 온 청구서는 어떤 형식으로 오든 한순간 생각해 볼 값어치가 있다. 이것이 어떤 설정보다도 값지다.
세 가지의 공통점을 보라. 어느 것도 PDF 사용을 그만두라거나 문서 전반을 의심하라고 요구하지 않는다. 현관문을 잠그는 일과 같다 — 값싸고 지루하며, 위험이 작지만 0은 아니기에 바로 그래서 합리적이다.
이 프로젝트가 받은 관심이 마땅한 이유
doompdf를 “인터넷 진기명기” 서랍에 넣고 지나가기는 쉬웠을 것이다. 나는 그보다 유용하다고 본다. 이유는 보안 연극과는 아무 상관이 없다.
대부분의 사람이 파일 형식에 대해 갖는 이해는 전적으로 그 형식이 무엇에 쓰이는가에 기대어 세워져 있다. 문서는 읽는 것. 스프레드시트는 숫자를 위한 것. 이미지는 보는 것. 이 그림은 거의 언제나 들어맞고, 그렇기에 좀처럼 흔들리지 않는다 — 그리고 그렇기에 “PDF는 능동적 내용을 담을 수 있다”는 설명은 대개 공손한 회의로 되돌아온다.
문서 안에서 실제로 플레이되는 게임은, 글이 천 단어로 힘겹게 하는 일을 십 초 만에 해낸다. 추상적인 주장을 클릭할 수 있는 무언가로 바꿔 놓는다.
그리고 더 깊은 논점은 PDF를 훌쩍 넘어선다. 형식은 수십 년에 걸쳐 기능을 쌓는다. 추가된 것 하나하나는 현실의 문제를 풀던 누군가에게 타당했다. 양식 검증은 정말로 쓸모가 있고, 자기 계산을 스스로 확인하는 문서도 마찬가지다. 그 결과 우리가 날마다 주고받는 평범한 것들은 그 이름이 암시하는 것보다 훨씬 많은 일을 할 수 있다. 그리고 어떤 능력이든 일단 명세에 들어가면, 그 명세를 읽는 누구에게나 열려 있다.
일상적인 파일에는 무엇이 남는가
여기 어느 대목도 PDF에 반대하는 주장이 아니다. 어디서든, 어떤 기계에서든, 몇 해가 지나도 똑같이 보이는 문서를 보내려면 여전히 PDF가 최선의 형식이다. 정말 어려운 문제였고 PDF가 그것을 풀었다. doompdf를 가능하게 하는 기능은 작성 가능한 세금 신고서를 가능하게 하는 기능과 똑같다.
이것은 자신이 무엇을 다루는지 알아 두자는 주장이다. 문서가 게임을 실어 나르게 하는 그 다재다능함이, 스크립트와 첨부와 숨은 레이어와 보낼 생각 없던 메타데이터도 실어 나르게 한다. 알아 둘 값어치가 있고, 그중 어느 것도 놀랄 이유는 아니다.
PDF Manipulator가 전적으로 당신의 컴퓨터에서만 돌아가는 이유의 일부도 여기에 있다. 파일을 합치거나 나누거나 변환할 때 관여하는 쪽은 적을수록 좋다 — 온라인 서비스가 음험해서가 아니라, 당신의 기계를 한 번도 떠나지 않은 문서가 남의 서버를 거쳐 온 문서보다 훨씬 따져 보기 쉽기 때문이다.
PDF 작업을 완전히 오프라인으로 — PDF Manipulator는 무료입니다 →


출처
- ading2210, GitHub의 doompdf — 소스 코드와 기술 설명. Emscripten 1.39.20, 여섯 단계 회색의 320×200 출력, 프레임당 약 80밀리초, GPL v2
- ading2210, GitHub의 linuxpdf — PDF 안의 TinyEMU RISC-V 에뮬레이터에서 돌아가는 리눅스, 부팅 30~60초
- 플레이 가능한 버전(Chromium 계열 브라우저)
- Eric Lawrence, Browser Security Bugs that Aren’t: JavaScript in PDF — 브라우저 PDF 엔진이 스크립트에 허용하는 것과 허용하지 않는 것
- Adobe, Restrict JavaScript API access in Acrobat
- DoomWiki, Licences — 1997년 12월 23일 코드 공개, 1999년 10월 3일 GPL 전환
- The Register, It’s Doom … running in a PDF file
- Ars Technica, This PDF contains a playable copy of Doom
