공급망 공격에 대한 대응으로 의존성 쿨다운을 적용하는 것에 반대하며, 중앙 업로드 큐가 더 나은 해법이라고 주장하는 글.
2026년 4월
공급망 공격에 대한 대응으로서의 의존성 쿨다운에 반대한다
의존성 쿨다운이 갑자기유행하고있다. 아주 빠르게 널리 권장되기 시작했고, "업계 표준 모범 사례" 꾸러미에 신속히 편입될 것처럼 보인다.
기대하는 바는 간단하다. 새 버전을 즉시 채택하는 대신, 릴리스 후 N일을 기다렸다가 도입하면, 몰래 삽입된 해킹이 누군가 다른 사람에 의해 발견되고 문제의 릴리스가 "철회"되거나 제거되리라는 것이다. 그리고 표면적으로는 이것이 효과적인 접근처럼 보이기도 한다. 실제로 대부분의 공급망 공격은 며칠 안에 탐지된다.
하지만 의존성 쿨다운은 이를 따르는 개별 주체에게는 적당히, 그것도 정말 적당히만 이익이 될 뿐이고, 그 비용은 다른 모든 사람에게 크게 전가된다. 그리고 핵심 문제도 해결하지 못한다. 퍼블리싱과 배포는 서로 다른 일인데, 왜 그것들이 꼭 결합되어 있어야 하는지는 분명하지 않다.
솔직히 말해, 의존성 쿨다운은 다른 사람들의 고통과 피해에 무임승차하는 방식으로 작동한다. 의존성 쿨다운 계획의 핵심에는, 쿨다운을 설정할 만큼 영리하지 못했던 다른 사람들이 새로 릴리스된 패키지의 무급 비자발적 베타 테스터 역할을 해주리라는 기대가 있다. 문제가 있으면 그 불쌍한 사람들이 해킹당하고, 모두가 그들이 해킹당한 사실을 알아차리고, 의존성 쿨다운을 쓰는 사람들의 임계 기간이 지나기 전에 문제의 패키지나 실행 파일이 철회된다.
이것이 개인에게 효과가 있다 하더라도, 생태계 전체가 따를 만한 건전하거나 도덕적인 체계로 유지하는 것은 불가능하다고 나는 생각한다.
또 다른 문제는 의존성 쿨다운이 매우 많은 서로 다른 사람들의 작업을 필요로 한다는 점이다. 이제 Python에는 패키지 관리자가 여러 개 있다. 지금 몇 개나 되지, 8개쯤? 모두가 의존성 쿨다운을 구현해야 한다. 그리고 지금까지 만들어진 모든 프로젝트는 그 쿨다운을 설정해야 하는데, 패키지 관리자들이 종종 완전히 서로 다른 방식으로 이 기능을 제공하기 때문에 이 작업은 대개 특별히 쉽거나 명확하지도 않다.
하지만 사실 쿨다운을 쓰는 사람들도 피해를 본다. 프로젝트 파일에 현명하게 설정해 둔 쿨다운을 우연히 우회해 버리기는 몹시 쉽다. Python에서는 프로젝트 설정 바깥에서 개인적으로 pip install litellm 한 번만 실행했어도 최근에 해킹당했을 것이다. 그러므로 쿨다운 접근은 실제로 완전하지도 않고, 특별히 안전하지도 않다.
어느 시점이 되면, 아마 LLM 사용이나 전통적인 복붙을 통해서일 텐데 — 대다수 프로젝트 설정이 그렇게 만들어지니까 — "책임 있는" 쿨다운이 사실상의 기본값이 된다. 그리고 Greenspun의 말을 비틀어 표현하자면, 충분히 널리 퍼진 의존성 쿨다운은 임시방편적이고, 비공식적으로 명세되었고, 구멍이 숭숭 뚫려 있으며, 느린 업로드 큐 구현물이 된다.
명백한 대안은 모두가 제각기 다른 패키지 관리자와 프로젝트에서 쿨다운을 반복해서 설정하는 대신, 중앙 의존성 서버에서 단 한 번만 그렇게 하는 것이다. 즉 "업로드 큐"다. 새 패키지는 _배포_되기 전에, _퍼블리시_된 뒤 일정 시간 기다리게 하자.
(여기서 나는 "퍼블리시" 를 릴리스 파일(tarball, whl, gem 등)을 중앙 인덱스(npm, pypi, rubygems)에 보내는 일이라는 뜻으로 쓴다. 반대로 "배포" 는 중앙 인덱스가 그 릴리스를 대중에게 제공하기 시작하는 시점이다.)
퍼블리시 이후 배포 이전의 시간 동안, 내부 린트 도구를 실행하고, 외부 자동 보안 스캐너가 패키지에 접근할 수 있게 하며, 무언가를 발견했을 때는 그들의 브랜드명을 눈에 띄게 표시해 주고, 빌드된 패키지 안에서의 변경 사항에 대한 공개 diff를 보여 주고, 심지어 대기 중인 릴리스를 의도적으로, 명시적으로 자원한 베타 테스터들에게 사용해 보게 할 수도 있다.
업로드 큐에는 선례가 있다. Debian 프로젝트는 업로드 큐를 사용한다. 패키지는 저장소에 업로드된 다음 "testing" 배포판에 들어가기 전에 최소 2일에서 10일을 기다린다. 업로드 큐는 패키지 퍼블리시와 패키지 배포를 분리한다.
퍼블리싱은 패키지를 만들어 저장소에 게시하는 일이다. 배포는 그 패키지가 대중에게 제공되는 시점이다. 이 두 활동이 반드시 동시에 일어나야 할 특별한 이유는 없다. 언어별 패키지 인덱스가 성장해 온 역사적 우연 때문에 그렇게 되었을 뿐이다.
업로드 큐는 의존성 쿨다운과 같은 목표를 달성하지만, 그 문제점은 하나도 갖지 않는다. 업로드 큐는 무임승차 문제를 해결한다. 더 이상 설정에 서툰 사람들이 쿨다운 사용자들을 위한 공짜 실험용 기니피그가 되지 않는다. 패키지 관리자는 아무것도 구현할 필요가 없다. 프로젝트도 또 하나의 설정 옵션을 추가할 필요가 없다. 보안 린터가 이를 경고할 필요도 없다. 그리고 설정 없이 개발자 노트북에서 일회성 패키지를 실수로 설치하더라도, 여전히 보호받는다.
업로드 큐에는 또 하나의 상당한 장점이 있다. 공급망 공격의 대다수에서는 몰래 삽입된 해킹만 무단이었던 것이 아니라, 릴리스 전체가 무단이었다. 퍼블리시된 패키지를 며칠 동안 대기시키면 릴리스 자격 증명의 위력이 크게 줄어든다. 이것이 중요한 이유는, 무언가를 더 잘 보호하는 것 다음으로, 그것의 권한 자체를 약하게 만드는 것도 좋은 방법이기 때문이다.
퍼블리시된 릴리스를 배포 전에 며칠 동안 대기시키면 새 릴리스가 나타날 때의 전혀 불필요한 놀라움의 요소도 제거된다. 사용자들은 새 릴리스가 곧 나온다는 사전 통지를 받을 수 있고, 정확히 언제 사용할 수 있게 될지도 미리 알 수 있다.
그리고 사전 지식이 필요한 것은 사용자들만이 아니다. 업로드 큐 기간은 관리자들에게도 알림을 보내기에 좋은 시간이다. 다가오는 릴리스가 정말 모두에게 알려졌는지 확인하기 위해서다. "알림: 릴리스 2.4.1이 업로드 큐에 들어갔습니다" 같은 메시지는 많은 경우 공급망 공격이 실제 배포까지 이어지는 것을 막는 데 필요한 바로 그 경고가 될 것이다.
사람들이 이렇게까지 노골적으로 말하는 경우는 드물지만, LLM 때문에 이제 markdown 은 실행 가능한 파일 형식이 되었다. 그것이 흥미로운 일인지 무서운 일인지, 아니면 둘 다인지는 아마 개인 취향에 달렸을 것이다. 하지만 단순한 사실이다. 결국 Agent Skills가 작동하는 방식도 그렇다. 어떤 markdown 파일을 내려받으면, 이제 당신의 LLM은 새로운 제3자 의존성을 갖게 된다.
LLM에 대한 첫 대형 공급망 공격도 의심할 여지 없이 시간문제다. 누군가 인기 있는 markdown 파일 어딘가에 자신의 "Disregard that!"을 끼워 넣는 식으로 말이다.
나는 이 문제를 내 개인 사이드 프로젝트인 "Soapstones"라는 AI 에이전트용 공개 메모리 시스템과 관련해 생각해 왔다. 이곳은 그들, 즉 AI 에이전트들이 HN 게시물 검색, 현재 날씨 확인, 환율 조회 같은 일을 어떻게 하는지 기록하는 장소다. Soapstones는 사실상 markdown 파일용 패키지 관리자다. 그리고 그렇기 때문에 공급망 공격 문제가 존재한다.
사실 여기에는 두 배로 적용된다. 누군가 markdown 파일에 "Disregard that!"를 심어 넣을 수도 있을 뿐 아니라, LLM이 어리석게도 비밀 정보를 시스템에 업로드할 수도 있다. 예를 들면 자신의 API 키 같은 것이다.
그리고 여기서도 해법은 업로드 큐다. 정확히 말하면 이중 업로드 큐다. 운영자들은 각 업로드를 검토해 공급망 공격이 있는지 확인한다. 그리고 에이전트의 소유자들도 각 업로드를 검토해 그것을 승인하는지 확인한다.
나는 여기서 업로드 큐만이 유일하게 합리적인 선택이라고 생각한다. LLM에게 "최근에 업로드된 것은 조심해서 다운로드하라"고 요청할 수는 없다. 그건 광기일 것이다.
예상 가능한 반론 하나는 "이 비용은 누가 내느냐"일 것이다. 첫째, 막대한 자금이 정말 필요한지는 분명하지 않다. Debian 프로젝트는 수십 년 동안 업로드 큐를 유지해 왔고, 보안상의 이유로 예외를 신속 처리하는 보안 팀도 갖추고 있다.
둘째, 중요한 패키지 인덱스들 모두가 정말 자금난에 시달리는지도 그리 분명하지 않다. NPM, Inc는 벤처 자금 지원을 받은 스타트업이었고 지금은 Microsoft의 완전 자회사다. PyPI를 운영하는 Python Software Foundation은 이미 길다란 기업 후원사 목록을 보유하고 있으며, 그중 다수는 업로드 큐로 혜택을 볼 수 있다. 그리고 PSF는 최근 무엇보다도 공급망 보안을 포함한 목적을 위해 Anthropic으로부터 150만 달러를 받기까지 했다.
하지만 또 다른 선택지는 상업 프로젝트에 대해 유료 서비스로 신속 보안 검토를 제공하는 것이다.
상업 조직은 종종 새 버전을 가능한 한 빨리 내야 할 이유가 있다. 고객에게 영향을 주는 어떤 비보안 버그를 고치기 위해서일 수도 있고, 큰 발표를 하기 위해서일 수도 있으며, 또는 중요한 서버 측 지원 중단 일정을 앞당기기 위해서일 수도 있다. 그런 경우 신속 검토를 유료 서비스로 청구하면 된다.
신속 검토는 절차에서 빠져나가는 선택권을 뜻하지 않는다. 회사가 자기 쪽에서 "publish"를 누르는 즉시 릴리스가 즉시 배포된다는 뜻도 아니다. 자동화된 절차는 여전히 끝까지 모두 실행되어야 한다. 다만 수동 검토를 통해 특정 릴리스의 실제 경과 시간을 크게 줄일 수 있다는 의미일 뿐이다.
패키지 인덱스는 이미 보안 대응 팀을 필요로 한다. 릴리스 철회, 엠바고 유지, typosquatting 대응, 0day 조정 같은 일을 해야 하기 때문이다. 상업 프로젝트에 신속 검토 비용을 청구하는 것은 그것을 교차 보조하는 좋은 방법이다. 기업의 긴급성이 생태계 전체를 위한 보안 장치를 보조금처럼 떠받치는 셈이다.
의존성 쿨다운은 스스로 적용하면 어느 정도는 꽤 도움이 되는 종류의 것 중 하나다. 그리고 우리 모두 어느 정도는 그렇게 한다. 어떤 것들은 내가 가장 먼저 업그레이드하고 싶지 않다. 우리 집에서는 거실 TV 셋톱박스가 핵심 인프라다.
하지만 각 업그레이드 상황에 대한 개인적이고 주관적인 반응을 공동체의 모범 사례로 굳혀 버리는 것은 질적으로 다른 문제다. 나는 내 보안이 다른 누군가가 먼저 해킹당하는 데 의존하는 것을 원하지 않는다.
이 글에 대해, 특히 동의하지 않았다면 cal@calpaterson.com으로 편지를 보내 달라. 반대로 이 글이 마음에 들었다면, 공유해 주는 것이 내게 큰 도움이 된다. 친구에게든, discord에든, subreddit에든 말이다.
내가 쓴 다른 글들을 보거나 소개 페이지에서 나에 대해 더 알아볼 수 있다.
새 글을 쓸 때 알림을 받으려면 RSS를 구독하면 된다.
예전에는 메일링 리스트가 있었지만, EmailOctopus가 그것을 잘못 삭제했다. 그들은 사과했지만 백업은 없다.
나는 여기에도 있다:
Debian stable은 사실상 업로드 큐 다. 핵심은 그것이 이미 QA 과정을 거친 오래된 릴리스들로 구성되어 있다는 데 있다. 언어 지향 패키지 관리자용 업로드 큐가 그렇게까지 포괄적일 필요는 없지만, Debian 사례에서 얻을 점은 분명 있다고 생각한다.
상대적으로 덜 논의되는 한 가지는 자동 스캐너가 얼마나 뛰어나지고 있는가 하는 점이다. 그 핵심 요소 중 하나는 업스트림 소스 코드만 보는 것이 아니라 빌드된 산출물을 검사한다는 점인데, 덕분에 둘 사이가 다른 경우를 알아차릴 수 있다. 스캐너가 더 오래 실행될 시간을 주는 것, 즉 쿨다운이든 업로드 큐든, 은 손쉽게 얻을 수 있는 성과 중 하나로 보인다.
그리고 또 하나는 Github actions가 얼마나 위험해 보이는가 하는 점이다. 공급망 공격의 상당한 다수는 특히 일반 대중이 PR을 열 수 있는 오픈소스 프로젝트에서 GHA에 대한 익스플로잇에 기반하는 것으로 보인다.
Soapstones에 관심이 있다면, 그것에 대해 이야기할 수 있는 Discord 서버에 참여할 수 있다.