인트로: 먼저 나에게 겨눠 보세요
남이 당신의 앱을 해부하기 전에, REA를 먼저 당신 자신의 앱에 돌려 보자. 우리는 일회용 클라우드 샌드박스에서 우리 라이브 사이트에 REA를 겨누고, 찾아낸 문제를 고친 뒤 풀 리퀘스트까지 올렸다.
REA는 수많은 영상이 남의 소프트웨어에 겨눈 리버스 엔지니어링 스킬이다. 우리 사이트에서는 13분도 안 걸렸고 쓰기 요청은 한 번도 보내지 않았는데, 어떤 웹사이트든 우리 메일링 리스트를 채울 수 있다는 사실이 드러났다. 또 우리 사이트에서 내려받는 JavaScript 안에 댓글 봇의 하루 한도가 그대로 들어 있다는 것도 찾아냈다. 수정 후에는 예전에 빠져나가던 그 요청이 거부된다.
결과는 같은 감사를 내 앱에 돌리는 여섯 가지 규칙이다. 일회용 샌드박스, 정확한 대상, 발견 분류하기, 번들에 실린 설정, 엔드포인트 브레이크, 그리고 수정 검증이다.
REA가 뭔지, 어떻게 설치하는지
REA는 Reverse Engineer Anything의 약자로, Claude Code가 당신이 배포한 앱을 뜯어볼 수 있게 해 주는 도구 모음이다. 리버스 엔지니어링은 완성품만 보고 어떻게 만들어졌는지 알아내는 일이다. 공장 도면 없이 자동차를 읽어 내는 정비사와 같다.
REA는 소스 코드 대신 번들을 읽는다. 번들은 당신의 사이트가 모든 방문자에게 실제로 보내는 JavaScript다. 이 번들에서 라우트, 페이지가 호출하는 엔드포인트, 실수로 남겨 둔 것들을 목록으로 뽑는다. 소스를 되돌려 주지는 못한다. 얻는 것은 증거뿐이고, REA 자신의 문서도 이것이 샌드박스가 아니라고 말한다.
설치 방법은 이렇다.
- 공식 패키지에서 REA를 설치하고 버전을 고정한다. 일주일에 릴리스가 여섯 번 나왔기 때문이다.
- Claude Code용 설정을 실행한다.
- 컴팩트 프로필을 켠다. 세션에 도구가 백 개 넘게 올라오기 때문이다.
- 공식 저장소에서만 설치한다. 악성코드가 든 가짜 사본이 이미 돌아다녔다.
샌드박스에서 설치를 돌렸을 때, 에이전트는 아무것도 건드리기 전에 패키지가 공식 저장소를 가리키는지부터 확인했다. 설정은 스킬만 설치했고 도구 서버는 설치하지 않아서, Claude Code는 같은 도구의 REA 명령줄 버전을 그대로 썼다. 설정 후에 도구가 보이지 않아도 아무것도 재시작할 필요가 없다. 같은 단계를 터미널에서 호출하면 된다.
규칙 1: 피해가 없는 곳에서 돌리기
첫 번째 규칙은 어디서 돌리느냐에 관한 것이다. 당신은 에이전트가 브라우저를 몰고, 내려받은 도구를 운영 중인 앱에 돌리게 하려 한다. 노트북에서는 그 에이전트가 당신의 키, 다른 프로젝트, 로그인된 모든 계정 바로 옆에 앉아 있다. REA의 보안 노트도 분명히 말한다. 이것은 샌드박스가 아니라고.
샌드박스는 일회용 머신이다. 무슨 일이 생겨도 그 안에 머물고, 끝나면 지우면 된다. 당신의 저장소에 일회용 샌드박스를 열고 감사 전체를 거기서 돌리자. 내 컴퓨터에서는 절대 안 된다.
우리는 Kosuke를 썼다. 일회용 클라우드 머신 안에서 당신 구독으로 Claude Code를 돌려 주는 서비스다. 저장소를 고르고 앱이 어떻게 시작되는지 배포 에이전트에게 알려 주면 프리뷰를 준다. 프리뷰는 실행 중인 앱이 뜨는 링크다. 채팅마다 자기만의 브랜치, 즉 코드의 자기 사본도 생기고, 끝에는 풀 리퀘스트가 붙는다. 우리 사이트를 가져오자 에이전트는 패키지 매니저와 헤드리스 브라우저를 설치하고, 메모리를 재서, 머신 크기를 스스로 골랐다. 몇 분 뒤 채팅 옆에서 우리 실제 사이트가 아무도 건드리지 않는 브랜치 위에서 돌고 있었다.
이전 테스트에서 만난 함정이 하나 있다. 새 Next.js 앱이 프리뷰에 뜨는데 페이지의 어떤 것도 반응하지 않았다. 해결은 Next 설정에 프리뷰 주소를 허용하는 한 줄을 넣는 것이고, 그러면 페이지가 살아난다.
한계도 있다. 이건 상자를 씌운 같은 Claude Code라서, 로컬 가상 머신이나 컨테이너도 같은 일을 한다. 중요한 건 브랜드가 아니라 상자다.
공개: Kosuke가 최상위 플랜을 무료로 제공했다. 가입 직후 'Promo code' 칸에 코드 AIDIVE2026을 입력하면 평소 10달러 대신 30달러 크레딧을 받는다.
규칙 2: 정확한 URL 하나, 모든 쓰기 차단
두 번째 규칙은 REA에게 실제로 무엇을 말하느냐다. 그냥 "내 앱을 감사해 줘"라고 하면 REA의 스킬은 멈추고 어떤 앱인지 되묻는다.
REA는 스스로 브라우저를 열지도 않는다. 그래서 디버그 포트를 켠 브라우저를 직접 시작해야 한다. 디버그 포트는 도구가 페이지의 모든 동작을 지켜볼 수 있게 하는 문이다. 이 순서로 준비하자.
- 디버그 포트를 루프백에 둔다. 내 머신만 닿는 주소다. 브라우저에는 새 프로필을 준다.
- 어떤 페이지가 로드되기 전에 모든 쓰기 요청을 차단한다. 그러면 감사는 사이트를 읽을 수는 있지만 폼을 제출하거나 무언가를 바꿀 수는 없다.
- 그다음에야 REA에게 읽어야 할 정확한 페이지를 준다.
우리 프롬프트에서는 무료 클럽의 페이지 두 개를 지정하고, 쉬운 말로 규칙을 하나 적었다. 라이브 사이트에는 절대 쓰기를 보내지 말 것. 이 규칙이 중요했던 이유는 그 페이지의 폼이 실제 사람들이 있는 진짜 메일링 리스트로 이어지기 때문이다. 에이전트는 규칙을 진지하게 받아들여, 읽기는 통과시키고 나머지는 모두 막는 작은 가드를 직접 짰다. 감사 중에 이 가드는 분석 스크립트가 보낸 시도 여섯 번을 막았고, 가입 폼에는 요청이 단 하나도 닿지 않았다.
그다음 REA가 제 몫을 했다. 페이지마다 살펴보고, 번들을 읽고, 스크린샷을 찍고, 스크립트를 저장소 밖으로 내보냈다.
한계는 REA가 붙어 있는 동안 로드되는 것만 본다는 점이다. 그 전에 일어난 일은 보고서에서 미확인으로 남는다. 그래도 이제 데이터 한 조각 건드리지 않고 쓴, 당신의 라이브 앱에 대한 보고서가 손에 있다.
규칙 3: 고치기 전에 모든 발견을 분류하기
세 번째 규칙은 고치기 전에 분류하라는 것이다. 이런 보고서에는 섬뜩한 줄이 가득해서 전부 한꺼번에 고치고 싶어진다.
REA의 스킬은 모든 결론에 관찰, 추론, 미확인 중 하나와 증거 ID를 붙이길 원한다. 본 것, 짐작한 것, 볼 수 없었던 것이고, 증거 ID는 직접 확인할 수 있는 영수증이다. 먼저 바깥에서 본 정보만으로 모든 발견을 이렇게 분류하고, 소스 파일을 하나라도 열기 전에 그 버전을 커밋하자. 그다음 소스를 읽고 각 줄을 진짜 유출, 의도된 설계, 오탐 중 하나로 표시한다.
우리 보고서에는 발견이 열다섯 개 있었다.
| 발견 | REA가 본 것 | 우리의 판정 |
|---|---|---|
| 가입 엔드포인트 | 제한도 없고 어느 사이트가 호출하는지 확인도 없어서, 어떤 웹사이트든 방문자의 브라우저가 아무 주소나 우리 리스트에 구독시키게 만들 수 있음 | 진짜 유출, 가장 심각 |
| 무료 팩의 이메일 게이트 | 팩 전체가 이미 로드한 페이지 안에 있다. 브라우저 콘솔에서 한 줄이면 게이트가 사라지고, 읽기 모드로도 글이 보임 | 의도된 설계 |
| 소스맵, 키, 쿠키 | 번들에는 없고 쿠키도 어디에도 없음 | 좋은 소식 |
게이트가 의도된 설계인 이유는 팩을 일부러 무료로 풀었기 때문이고, 우리 코드도 고장 난 폼이 무료 페이지를 가려서는 안 된다고 말한다.
한계는 미확인 열이다. REA는 당신의 서버가 무엇을 하는지 볼 수 없으니, 그런 줄은 서버 코드를 읽어서 정리해야 한다.
규칙 4: 번들에 내 설정이 실려 나간다
네 번째 규칙은 번들이 무엇을 싣고 가느냐에 관한 것이다. 공유 설정 파일 하나가 당신도 모르게 모든 방문자에게 가 버릴 수 있다.
과정은 이렇다. 한 헬퍼에서 설정을 가져오고, 작은 인터랙티브 컴포넌트 둘이 그 헬퍼를 쓴다. 번들러는 코드를 브라우저가 내려받는 파일로 묶는 도구인데, 그 컴포넌트가 어떤 키를 쓰는지 구분하지 못해서 전부 실어 보낸다.
REA가 우리 JavaScript에서 바로 그걸 찾아냈다. 우리 사이트 설정 전체가 파일 하나에 들어 있었다. 메일링 리스트 ID, 빌드 폴더, 우리 영상에 달린 댓글에 답하는 봇의 한도까지. 그 봇이 하루에 보내는 답글 수가 백 개이고, 오류가 몇 번이면 안전 스위치가 내려가는지도 적혀 있었다. 그걸 가져다 쓴 두 컴포넌트는 사이트 이름과 언어 목록만 읽었는데도 말이다.
규칙은 이렇다. 배포된 JavaScript에서 내 설정 키를 검색하고, 클라이언트 컴포넌트에는 읽는 필드만 넘긴다. 샌드박스에서 에이전트는 설정을 그 필드만 담은 아주 작은 브라우저용 버전으로 쪼갰고, 나머지는 서버에 남겼다. 서버 키가 배포 파일에 다시 나타나면 실패하는 빌드 단계도 추가해서, 되돌아갈 수 없게 했다.
이 중 비밀번호는 없었다. 하지만 그 파일 안의 모든 것은 공개이므로, 비밀은 서버 변수에만 둬야 한다.
규칙 5: 열린 엔드포인트마다 브레이크를
다섯 번째 규칙이 우리의 진짜 유출을 막았다. 이메일 리스트, AI 모델, 문자 메시지 게이트웨이처럼 유료 서비스를 부르는 공개 폼이 있다면 어디에든 해당한다. 하루 오후에 짠 작은 서버 함수로 그 서비스를 호출하고 있을 것이다. 우리 함수는 이메일을 받아 그대로 메일링 리스트에 넘겼고, 다른 어떤 웹사이트든 방문자의 브라우저가 거기에 요청을 보내게 만들 수 있었다.
보안 업계의 체크리스트도 분명히 말한다. 접근 제어는 공격자가 바꿀 수 없는 코드, 곧 당신의 서버에서만 효과가 있다고. 그러니 그런 엔드포인트마다 브레이크를 건다.
- Origin 확인. Origin 헤더는 브라우저가 요청에 찍는 도장으로, 어느 사이트가 보냈는지 알려 준다. 그래서 다른 웹사이트의 폼은 거부된다.
- 속도 제한. 한 방문자가 짧은 시간에 보낼 수 있는 요청 수의 상한.
- 서버에서 확인하는 동의. 체크한 상자가 실제로 요청과 함께 전달된다.
샌드박스에서 에이전트는 이 셋을 모두 우리 Worker에 써 넣었다. Worker는 방문자가 페이지를 열 때 페이지 앞에서 돌아가는 작은 함수다. 그다음 진짜가 아니라 가짜 메일링 서비스를 상대로 테스트했고, 모든 요청이 정확히 거부되어야 할 지점에서 거부됐다. 엉뚱한 사이트에서 보내면 거부된다. 1분에 여섯 번째 요청도 거부된다. 동의가 없으면 반려된다.
한계는 스크립트가 Origin 도장을 위조할 수 있고, 속도 제한은 위치별로 세기 때문에, 근본적인 해결책은 이메일 이중 확인이라는 점이다.
규칙 6: 다시 돌리고, 직접 확인하고, PR 올리기
여섯 번째이자 마지막 규칙은 수정을 증명하는 것이다. 초록색 체크 표시가 줄줄이 나올 때가 바로 눈여겨보기를 멈추는 때이기 때문이다. 데스크톱 앱에 REA를 테스트한 한 개발자는 HackerNoon에, REA가 앱에 실제로 있던 진입점을 놓쳤다고 썼다.
그러니 수정된 빌드에 같은 REA 단계를 다시 돌리고, 수정마다 터미널에서 직접 확인한 다음에야 풀 리퀘스트를 열자.
수정된 빌드에서는 예전에 우리 가입 폼으로 빠져나가던 요청이 거부된다. 서버 키는 배포된 어느 파일에서도 사라졌고, 보안 헤더가 붙었고, Worker 테스트는 실패에서 통과로 바뀌었다. 무료 팩의 게이트는 우리가 정한 대로 열려 있었고, 보고서는 줄마다 그 사실을 옆에 적어 두었다.
그다음 에이전트가 풀 리퀘스트를 열었다. 보고서가 그 안에 있는 건 프롬프트에서 요청했기 때문일 뿐이다. Kosuke가 만드는 테스트 체크리스트는 세션 안에만 남았고, 풀 리퀘스트 자체에는 아무것도 올라오지 않았다. 리뷰어가 GitHub만 읽는다면, 수정 전과 후의 보고서를 풀 리퀘스트에 직접 넣어 두자.
이후 같은 변경을 우리 코드에 가져왔고, 다음 사이트 배포 때 라이브로 나간다.
결론: REA를 나에게 겨눌 때
전체 과정은 이랬다. REA를 일회용 샌드박스에서 우리 라이브 사이트에 겨누고, 모든 발견을 분류하고, 진짜 유출을 고치고, 다시 감사하고, 풀 리퀘스트로 올렸다. 이 모든 걸 정당화한 발견은 첫 번째였다. 어떤 웹사이트든 우리 가입 폼에 아무나의 주소를 채울 수 있다는 것.
공개 폼이나 유료 서비스가 붙은 무언가를 출시하기 전에 이 감사를 돌리고, 배포되는 내용이 바뀔 때마다 다시 돌리자. 내 것이 아닌 소프트웨어에는 돌리지 말자. REA 자신의 면책 조항이 내가 소유했거나 검사할 권한이 있는 소프트웨어로 사용을 제한하기 때문이다. 그리고 서버 코드를 읽는 일을 대신할 수는 없다. 미확인은 바로 거기에 있다.
규칙 하나만 지킨다면 이것이다. 나에게, 상자 안에서 돌리고, 분류한 것만 고치자.
정확한 프롬프트, 분류 표, 우리가 배포한 Worker 수정은 이 영상의 무료 키트에 들어 있다.
AIDive