브라우저 확장 지갑: 전 사이트 권한과 조용한 업데이트의 위험
지갑 확장 6종의 현재 빌드를 받아 manifest를 읽었습니다. 여섯 모두 방문하는 모든 사이트를 읽고, 업데이트는 확인 없이 도착합니다. 교환에 무엇을 의미하는지.
지갑 확장 프로그램은 설치할 때 '모든 웹사이트의 데이터를 읽고 변경'할 권한을 요구합니다. 다크패턴이 아니라 구조입니다. 확장이 프로바이더 객체를 모든 페이지에 주입해야 사이트의 교환 버튼이 그것을 찾을 수 있습니다. 부작용은 같은 소프트웨어가 두 능력을 동시에 갖는다는 점입니다. 폼에 붙여넣은 주소를 읽는 능력, 그리고 사이트가 요청할 때 서명하는 능력. 2026-10-28, 저희는 구글 자체 업데이트 엔드포인트에서 주요 지갑 확장 6종의 현재 빌드를 받아 압축을 풀고 manifest를 읽었습니다. 이 글은 그 파일들이 실제로 무엇을 선언하는지, 왜 권한 팝업보다 업데이트 경로가 더 의심스러운지, 그리고 저희 같은 교환 사이트가 무엇을 할 수 있고 없는지를 다룹니다.
지갑 확장은 실제로 무엇인가
받은 6종은 모두 Manifest V3입니다. V3가 문제의 모양을 바꿨기 때문에 짚을 가치가 있습니다. V3 지갑은 상주 페이지가 없는 서비스 워커, document_start(사이트 자체 JS보다 먼저)에 주입되는 콘텐츠 스크립트, 그리고 그 스크립트가 어떤 오리진을 건드릴 수 있는지 정하는 host 권한으로 구성됩니다. 콘텐츠 스크립트는 격리된 월드에서 돌아 페이지 변수를 직접 읽지는 못하지만 DOM 읽기와 수정은 가능하고, 주소 입력란을 바꾸기엔 충분합니다. 서명은 별개의 명시적 단계로, 지갑이 자체 창을 열고 사용자가 승인합니다. 놓치기 쉬운 것은 '읽기' 권한입니다. 설치 시 한 번, 대부분이 1초 만에 닫는 팝업에서 부여되기 때문입니다. 참고로 MetaMask의 현행 manifest는 cookies, webRequest, identity, offscreen을 포함한 11개 권한을 요구하고 clipboardRead를 선택 권한으로 둡니다.
2026-10-28 06:02 UTC에 측정한 권한표
읽은 패키지는 MetaMask 13.54.0.0, Phantom 26.35.0, Rabby 0.94.13, Keplr 0.13.53, Trust Wallet 26.42.4, OKX Wallet 4.21.0입니다. 6종 모두 모든 http/https 오리진 접근을 선언합니다. MetaMask는 ws, wss, file, localhost:8545를 더하고, 어떤 웹사이트든 메시지를 보낼 수 있게 허용한 유일한 확장입니다(externally_connectable의 확장 id가 와일드카드). Rabby는 가장 거친 all_urls를 쓰고, Keplr는 all_urls에 document_start로 주입하며, Trust Wallet은 clipboardWrite와 gcm을, OKX는 모든 사이트에 더해 solscan.io, twitter.com, x.com에 콘텐츠 스크립트를 고정합니다. 패키지는 16.4 MB에서 54.7 MB, 파일 수 103에서 1,187, 압축 해제 JS는 15.5 MB에서 92.5 MB입니다. 마지막 숫자가 공격면의 정직한 척도입니다. 수십 MB의 제3자 코드가 열어 보는 모든 페이지에 상시 권한을 갖고, 다른 누군가에 의해 갱신됩니다.
조용한 업데이트, crx_id가 지키는 것과 못 지키는 것
CRX3는 작은 protobuf 헤더와 zip의 조합입니다. 6종 모두 같은 형태였습니다. RSA 서명 증명 2개, ECDSA 증명 1개, 그리고 16바이트 crx_id를 담은 signed_header_data. 이 id의 16진수를 a부터 p까지 문자로 옮기면 스토어에서 보는 32자 확장 ID가 됩니다. 6종 모두 정확히 일치함을 확인했습니다. 즉 키가 ID에 묶여 있어 다른 누구도 그 ID의 빌드를 배포할 수 없습니다. 그러나 게시자는 무엇이든 배포할 수 있고 Chrome은 아무에게도 묻지 않고 설치합니다. 검사는 방금 쓴 것과 같은 공개 엔드포인트로 백그라운드에서 돌고, 브라우저 버전이 인자로 전달되며, 새 코드는 다음 페이지 로드에서 살아납니다. 읽어야 하는 변경 로그도 동의 버튼도 없습니다. 그래서 실제 사고는 한 층 아래, 의존성에서 납니다. @solana/web3.js는 1.95.6이 2024-12-03 15:10:07 UTC, 1.95.7이 15:20:23에 올라갔고 둘 다 지금은 registry 버전 목록에서 사라졌으며 정상판 1.95.8이 20:25:40에 나왔습니다. 5시간 15분입니다. @ledgerhq/connect-kit은 2023-12-14에 1.1.5가 08:49:04, 1.1.6이 09:44:57, 1.1.7이 10:37:24, 정상판 1.1.8이 13:18:35로 4시간 30분. 두 사건 모두 창은 며칠이 아니라 자동 설치가 해당 버전을 집어갈 때까지의 시간이었습니다. (모네로 확인 대기)
교환에 필요한 것, 그리고 확장이 여전히 할 수 있는 것
여기서 저희 제품 형태가 중요해집니다. VeilSwap 주문은 다섯 개 필드뿐입니다. 파는 자산, 받는 자산, 수량, 지급 주소, 환불 주소. 계정도 이메일도 지갑 연결도 서명도 없습니다. 프런트엔드에서 window.ethereum, WalletConnect, wagmi를 grep하면 0건입니다. 흐름 어디서도 지갑에 무엇을 요구하지 않기 때문입니다. 그렇게 최대 리스크 부류인 '읽지 않고 누르는 승인 팝업'이 사라집니다. 그러나 '읽기' 권한은 남습니다. 지갑 확장은 veilswap.io에서도 document_start로 돌며 주소 입력란을 볼 수 있습니다. 주소 형식과 체크섬은 주문 생성 시 서버에서 검증되어 오타는 막지만 형식이 정상인 교체는 막지 못합니다. 규모 감각으로 06:04 UTC 실측 견적: 100 USDT-TRC20이 0.14408925 XMR, 5,000이 8.06917242 XMR. XMR당 694.01 대 619.64 USDT로, 12% 차이는 주문당 고정 비용이며 지갑이 관여하는 숫자가 아닙니다. 1 XMR은 589.282718 USDT, 0.05 BTC는 6.54643747 XMR(130.92875 XMR/BTC, BTC당 약 77,154달러). 카탈로그는 520개 자산, 73개 네트워크. (XMR→USDT 출구 루트)
여섯 가지 행동과 세 가지 오해
첫째, 지갑 전용 브라우저 프로필을 하나 두고 교환은 지갑 확장이 전혀 없는 프로필에서 합니다. 주소는 복사·붙여넣기로 오가면 충분합니다. 둘째, 확장 관리 화면에서 각 지갑의 사이트 접근을 '클릭 시' 또는 짧은 허용 목록으로 바꾸고 업데이트마다 다시 봅니다. 셋째, 실제 자금을 옮기기 전에 설치된 버전과 스토어 표기를 대조합니다. 위 버전들은 06:02 UTC에 배포되던 것이지 당신 것이 아닙니다. 넷째, 시드 구문을 요구하는 것은 팝업 문구와 무관하게 공격으로 취급합니다. 웹 흐름에 필요하지 않습니다. 다섯째, 금액이 정당화되면 하드웨어로 서명하고 주소는 브라우저가 아니라 기기 화면에서 읽습니다. 여섯째, 업데이트로 권한 목록이 늘면 확인을 누르는 대신 삭제하고 다시 설치합니다. 세 가지 오해: 스토어 심사는 악성 업데이트를 막지 못합니다(업데이트 심사는 최초 제출보다 가볍고, 위 6종은 각각 233, 230, 64, 31, 234, 392개의 JS 파일을 담고 있습니다). 시크릿 모드는 샌드박스가 아닙니다(명시적으로 허용해야 확장이 돌고, 돌면 그 페이지도 읽습니다). 그리고 지갑 수를 줄여도 리스크가 선형으로 줄지 않습니다. 모든 사이트 권한을 각 확장이 독립적으로 갖기 때문입니다. (모네로 확인 대기)
짧게 정리합니다. 브라우저 지갑은 하드웨어 기기로서의 지갑이 아니라 페이지를 읽고 덤으로 키를 들고 있는 프로그램이며, 게시 키를 쥔 사람에 의해 조용히 교체됩니다. 교환에 그것은 필요 없습니다. 주문에는 주소와 금액만 있으면 됩니다. 연결과 서명을 요구하는 사이트는 거래가 요구하는 것보다 많은 것을 요구합니다. 지갑은 한 프로필에 가두고 교환은 다른 프로필에서 하며, 주소는 복사한 원본에서 한 글자씩 확인하십시오. 읽어 본 적 없는 92 MB의 코드를 신뢰하는 것보다 훨씬 싼 요구입니다. (모네로 확인 대기)