서드파티 스크립트는 공급망 리스크입니다

서드파티 스크립트는 당신이 쓰지 않은 코드이고, 당신이 통제하지 않는 회사가 제공하며, 당신의 페이지 안에서 사용자들의 세션과 함께 실행됩니다 — 공급망 용어로 말하면, 릴리스도, 검토도, 알림도 없이 언제든 자기 코드를 바꿀 수 있는 의존성입니다. 2026년 10월, 그 추상적인 리스크는 보도에 따르면 구체적인 손실이 되었습니다. 주요 거래 사이트가 불러오던 성능 모니터링 스크립트가 사용자를 빼내도록 만들어진 것으로 교체된 것입니다. 이 글은 보도된 내용, SRI가 실제로 막는 것, 버전 고정이 그 해시에 앞서는 이유, 자체 호스팅이 더 나은 답이 되는 경우, 그리고 목록을 정직하게 유지하는 짧은 감사 루틴을 살펴봅니다.

보도된 Polymarket 사건

보도에 따르면 2026년 10월 29일, Polymarket의 국제 사이트는 사용자들이 계좌에서 자금이 빠져나간다고 알린 뒤 거래를 취소 전용 모드로 전환했고, 약 한 시간 뒤 거래가 재개됐습니다. 보도에 따르면 회사 자체의 성명은 사건을 침해된 서드파티 제공업체 탓으로 돌렸고, 이 사안이 법 집행 기관에 회부됐다고 말했으며, 피해를 본 사용자를 온전히 보상하겠다고 약속했습니다. 회사의 10월 30일 포스트모템에 기반한 보도는 공격으로 가져간 금액을 약 270만 달러, 거래 중단으로 인한 손실에 대한 선의의 지급을 포함하면 총 환불을 390만 달러로 전했습니다. 보도에서 인용된 독립적인 온체인 분석은 수백 개의 지갑에 걸쳐 비슷한 수치, 약 270만 달러를 추적했습니다. 이 수치들 중 어느 것도 여기에서 독립적으로 검증되지 않았습니다 — 그것들은 보도의 수치이며, 이 글도 그렇게 취급합니다.

보도에 따르면 일반화할 수 있는 부분은 그 메커니즘입니다. 보도에서 인용된 연구자들은 악성 코드를 웹사이트 성능 벤더의 실제 사용자 모니터링(RUM) 스크립트와 연결했습니다 — 방문자의 브라우저에서 페이지 로드 속도를 재는 것만이 일인 작은 파일로, 고객별로 벤더의 CDN에서 임베드됩니다. 보도에 따르면 그 파일은 대상 사이트를 위해 특별히 쓰인 페이로드로 교체됐습니다. 그것은 로그인된 세션 안에서 작동했고, 페이지 안에 이미 있던 사이트 자체의 거래 기계를 사용했으며, 포지션과 자금을 공격자가 통제하는 목적지로 옮겼습니다. 보도에 따르면 스마트 계약 결함도, 도난당한 비밀번호나 개인 키도 관여하지 않았습니다 — 교체된 스크립트는 브라우저 입장에서는 그저 페이지 그 자체였습니다. 그 설명의 세부 사항 하나하나가 이후의 정밀 검사를 견딜지는 교훈에 있어서는 본론에서 벗어납니다. 공격의 형태 — 벤더 파일 하나, 한 번의 교체, 모든 방문자에 의한 실행 — 가 이 부류 사건의 표준 형태입니다.

서드파티 스크립트는 당신의 코드이지만, 릴리스 절차는 남의 것입니다

고전적인 script 태그에는 샌드박스가 없습니다. 벤더의 CDN에서 불러온 코드는 당신 자신의 번들과 같은 접근권으로 당신의 출처 안에서 실행됩니다. DOM을 읽고 바꿀 수 있고, 입력 중인 양식 값을 읽을 수 있으며, 사용자의 세션으로 당신의 API를 호출할 수 있고, 찾은 것을 어디로든 보낼 수 있습니다. 서드파티 JavaScript에 관한 OWASP 가이드는 세 가지 리스크를 분명히 이름 붙입니다 — 클라이언트 애플리케이션 변경에 대한 통제의 상실, 클라이언트 시스템에서의 임의 코드 실행, 제3자에 대한 민감 정보의 공개 — 그리고 셋 모두 그 하나의 사실에서 따라옵니다. 당신의 검토 절차, 코드 동결, 변경 위원회는 당신 자신의 빌드에서 끝납니다. 벤더의 파일은 벤더가, 벤더를 침해한 공격자가, 또는 도메인이 만료됐을 때 그것을 재등록한 사람이 편집할 수 있습니다.

그 비대칭이 바로 "우리는 이 벤더를 신뢰합니다"가 통제가 아닌 이유입니다. 신뢰는 오늘 누구의 스크립트를 받아들일지를 정합니다. 그 URL이 내일 무엇을 제공할지에 대해서는 아무 말도 하지 않으며, 내용이 바뀔 때 어떤 신호도 주지 않습니다. 작동하는 통제는 신뢰를 제거하는 것(파일을 직접 제공), 신뢰를 제약하는 것(어떤 스크립트든 할 수 있는 일과 데이터를 보낼 수 있는 곳을 제한하는 Content-Security-Policy), 또는 불러올 때마다 기계적으로 검증하는 것 — 그것이 SRI의 역할입니다 — 입니다. 목록부터 시작하세요. 당신이 가진 줄 모르는 스크립트에는 그 셋 중 어느 것도 적용할 수 없으며, 마케팅 태그, 지원 위젯, 모니터링 임베드를 세면 대부분의 사이트는 소유주가 예상하는 것보다 많은 스크립트를 가지고 있습니다.

SRI가 막는 것 — 그리고 막지 못하는 것

Subresource Integrity는 브라우저 메커니즘으로, W3C가 명세하고 MDN이 문서화했습니다. 페이지는 태그의 integrity 속성에 기대하는 파일의 암호화 해시를 선언하고, 브라우저는 실제로 다운로드한 것을 해시하며, 조금이라도 다르면 파일 실행을 거부합니다. 교차 출처 파일에 대해서는 태그에 crossorigin="anonymous"도 필요하고, 브라우저가 검사를 할 수 있도록 서버는 CORS 헤더를 보내야 합니다. 고정된 라이브러리에 적용하면 SRI는 조용한 교체를 시끄러운 실패로 바꿉니다. 도착한 파일은 당신이 검토한 파일과 바이트 단위로 동일하거나, 전혀 실행되지 않거나, 둘 중 하나입니다. 보도된 사건의 모니터링 스크립트가 그런 식으로 불러와진 고정 파일이었다면, 교체된 페이로드는 사용자 세션에서 실행되는 대신 검사에 실패했을 것입니다 — 이 조건문이 그 주장의 정직한 형태입니다. 왜냐하면 그 특정 임베드가 해시 가능했는지는 동적인 고객별 파일에 관한 문제이며, 그것이 바로 아래의 어려운 경우이기 때문입니다.

SRI가 막지 못하는 것도 그만큼 중요합니다. 내용이 바뀌도록 되어 있는 스크립트 — 태그 관리자 컨테이너, 개인화와 동의 로더, 고객별로 생성되는 파일 — 에는 도움이 되지 않습니다. 고정할 안정적인 해시가 없기 때문입니다. 당신이 해시한 파일을 판단하지도 않습니다. 충실히 전달된 스크립트라도 설계상 엿보기 좋아하고, 허술하고, 악성일 수 있으며, SRI는 영원히 기꺼이 그것을 검증할 것입니다. 다른 스크립트가 런타임에 주입하는 스크립트는 다루지 않고, 당신 자신의 인프라에서 제공되는 퍼스트파티 파일도 보호하지 않으며, 실행된 정당한 스크립트가 수집하는 데이터에 대해서는 아무것도 하지 않습니다. SRI는 하나의 기계적 보장 — 바로 이 바이트들, 아니면 아무것도 아님 — 이며, CSP, 벤더 검토, 그리고 애초에 세션 수준 접근을 얻는 제3자를 최소화하는 것의 대체가 아니라 그 옆에서 자기 자리를 얻습니다. 이 사이트의 보안 헤더 검사는 그 쌍의 CSP 쪽을 채점합니다.

버전을 고정하세요, 그렇지 않으면 해시는 설 수 없습니다

SRI에는 악성보다 더 많은 감사를 실패하게 만드는 전제 조건이 있습니다. URL은 항상 같은 바이트를 돌려줘야 합니다. latest 주소, 떠다니는 메이저 버전, 또는 벤더가 재생성하는 고객별 파일 위에 고정된 해시는, 벤더가 첫 업데이트를 배포하는 순간 깨지는 해시입니다. 그리고 자기 탓인 SRI 실패에 한 번 깨어난 팀은 주소를 고치는 대신 그 속성을 제거하는 경향이 있어, 페이지를 측정하지 않은 것보다 나쁘게 남깁니다. 오래가는 순서는 반대입니다. 먼저 URL을 정확한 버전을 이름으로 지정하도록 바꾸고([email protected], /v2.4.0/), 그 버전을 한 번 검토한 다음, 바로 그 파일의 해시를 구하세요. 그러면 버전 올리기는 의도적인 이벤트 — 새 URL, 새 해시, 하나의 커밋 — 가 되어, 사용자를 통해 발견하게 되는 주변 변화가 되지 않습니다.

고정에는 대가가 있고, 정직함은 그것을 이름 붙일 것을 요구합니다. 고정된 라이브러리는 벤더로부터의 조용한 보안 패치를 더 이상 받지 않으므로, 고정은 릴리스를 추적하고 의도적으로 올릴 의무를 만듭니다. 그것은 벤더링된 의존성이 지는 의무와 같은 의무입니다. 그것은 감당할 수 있는 의무 — 릴리스 노트와 캘린더 알림이 그것을 덮습니다 — 이며, 그것이 대체하는 대안보다 엄밀히 낫습니다. 그 대안에서는 업데이트가 벤더의 속도로 검토 없이 도착하고, 파손은 당신의 속도로 예고 없이 도착합니다. 그 쌍을 하나의 실천으로 취급하세요. 고정은 내용을 주소 지정 가능하게 만들고, 해시는 검증 가능하게 만들며, 감사는 둘 중 어느 것도 조용히 썩지 않았음을 보장합니다 — CMS 마이그레이션이 편집해 없앤 버전 문자열은 부족한 해시만큼 흔하며, 눈으로 알아채기가 조금 더 어려울 뿐입니다.

자체 호스팅, 그리고 감사 루틴

가장 중요한 스크립트들에 대해서는 더 무딘 선택지가 있습니다. 파일을 직접 제공하는 것입니다. 자체 호스팅은 벤더의 서버, 계정, 도메인을 런타임 공급망에서 완전히 제거하고, 당신의 일반적인 배포 파이프라인이 파일을 검토하고 해시하게 하며, 벤더의 CDN이 작동하지 않을 때도 계속 작동합니다. 절충은 실재합니다 — 벤더의 엣지 캐시와 자동 업데이트를 포기하고, 그 보안 수정을 직접 배포할 의무를 떠안으며, 일부 벤더의 라이선스나 고객별 생성 파일은 아예 그것을 허용하지 않습니다 — 그러므로 현명한 분할은 중요도에 따릅니다. 민감한 페이지의 작고 고정된 라이브러리는 자체 호스팅하고, CDN에 남는 것은 고정하고 해시하며, 고정도 호스팅도 할 수 없는 동적 태그는 거버넌스(게시 제한, 변경 검토, CSP)로 다스리고, 누구도 정당화할 수 없는 스크립트는 보이는 즉시 삭제하세요. 제거된 스크립트 하나마다, 당신이 더 이상 갖지 않는 공급망이 하나씩 줄어듭니다.

이것을 사실로 유지하는 루틴은 실제로 실행할 수 있을 만큼 짧습니다. 분기마다 — 그리고 재설계, CMS 마이그레이션, 새 벤더가 있을 때마다 — 핵심 페이지 템플릿에 대해 서드파티 스크립트 및 SRI 감사를 실행하세요. 그것은 정적 HTML이 참조하는 모든 스크립트, 어떤 것이 서드파티인지, 어떤 것에 무결성이 부족한지, 어떤 것이 고정되지 않았는지를 나열하고, 가져올 수 있는 처음의 부족한 해시들에 대해 붙여넣을 수 있는 sha384를 계산합니다. 영향 순서대로 고치세요 — 세션, 결제, 개인정보 페이지를 먼저 —, 그 다음 SSL 채점기와 헤더 검사로 전송 계층과 헤더 계층을 확인하고, 마지막으로 태그 관리자에서 마무리하세요. 거기에서는 런타임에 주입되는 스크립트를 정적 감사가 볼 수 없습니다. 그 게시자 목록과 변경 이력을 배포 로그에 줄 것과 같은 의심으로 검토하세요. 분기마다 15분 — 보도된 사례에서 약 한 시간 만에 수백만에 이른 사건 부류에 맞서는 것입니다.

출처 및 더 읽을거리

자주 묻는 질문

SRI가 보도된 Polymarket 사건을 막았을까요?

보도에 따르면 페이로드는 페이지가 이미 신뢰하던 벤더 URL의 파일을 교체함으로써 도착했습니다 — 그것은 바로 SRI가 거부하기 위해 존재하는 교체이며, 올바른 무결성 해시를 가진 고정 파일에 대해서는 그렇습니다. 정직한 단서는, 문제의 임베드가 보도에 따르면 고객별 모니터링 파일이었다는 것입니다. 그런 동적 파일은 SRI에게 어려운 경우이며, 거기에서 적용할 수 있는 통제는 거버넌스 쪽입니다. 엄격한 게시 통제, 스크립트가 닿을 수 있는 범위에 대한 CSP 제한, 신속한 제거 경로입니다. 이 글의 수치와 메커니즘은 보도와 보도된 회사의 포스트모템 그대로이며 — 여기에서 독립적으로 검증되지 않았습니다.

태그 관리자에 SRI를 넣을 수 있나요?

유용하게는 넣을 수 없습니다. 태그 관리자 컨테이너는 URL은 그대로인 채 바뀌도록 설계되었으므로, 당신이 고정하는 어떤 해시든 다음 게시 — 보통 당신 자신의 게시 — 에서 깨집니다. 대신 관리자 자체를 보호하세요. 게시 권한을 제한하고, 컨테이너 변경의 검토를 요구하며, Content-Security-Policy를 사용해 주입된 태그가 실행할 수 있는 것과 데이터를 보낼 수 있는 곳을 한정하세요. SRI는 하나의 URL이 하나의 파일을 뜻하는 고정 라이브러리를 위해 남겨 두세요.

페이지의 스크립트를 얼마나 자주 다시 감사해야 하나요?

안정적인 사이트에서는 분기마다가 실행 가능한 하한이며, 여기에 템플릿이나 벤더를 바꾸는 사건이 있을 때마다 한 번씩 더합니다. 재설계, CMS 마이그레이션, 새 분석 도구나 지원 도구, 그리고 벤더의 보안 공지입니다. 감사 자체는 몇 분이면 됩니다 — 비싼 실패 형태는 그것을 다시 실행하지 않는 것이 아니라, 끝난 캠페인이 추가한 스크립트가 주인 없이 2년 뒤에도 여전히 불러와지는 것입니다.