Trawling
발견 출처 Reddit/발행

Nothing Installs at Our Company Until It's a Week Old

한 회사, npm·PyPI 신버전 설치를 7일 늦추는 프록시 운영

한 회사가 프록시를 두고 npm 계열과 PyPI 새 버전은 7일, pub는 3일 대기한 뒤 개발 환경에 제공합니다. 대기 중인 버전은 목록에서 숨기며 잠금 파일이 이를 고정하면 다운로드가 404로 실패합니다. 일부 생태계와 직접 레지스트리 주소를 쓰는 잠금 파일은 이 규칙을 우회합니다.

본문

한 기술 블로그 운영자가 회사에서 공개 패키지 레지스트리와 개발 환경 사이에 프록시를 둔 운영 경험을 공개했습니다. 회사는 git-pkgs/proxy를 통해 npm, pnpm, Yarn, Bun과 pip, uv 패키지를 받을 때 게시 후 7일을 기다립니다. Dart·Flutter의 pub는 3일 대기하고 Maven·Gradle·Go는 캐시를 거치지만 대기 규칙을 적용하지 않습니다. CocoaPods, Google Maven, Docker 이미지는 프록시 경로 밖입니다.

작성자가 7일을 택한 근거는 악성 패키지의 짧은 유통 시간입니다. axios, Lightning, TanStack, keyv, LiteLLM 관련 공급망 공격 다섯 건을 살펴본 결과 악성 버전은 모두 게시 후 5시간 안에 제거됐다고 설명했습니다. Huntress는 axios 감염 사례를 게시 89초 뒤에 관측했습니다. 프록시의 대기는 새 버전이 회사 설치 경로에 들어오기까지 시간을 벌어, 사고를 발견하고 해당 버전을 차단할 여지를 둡니다.

프록시는 패키지 파일을 분석해 악성 여부를 판정하지 않습니다. 게시 연령을 기준으로 대기 중인 버전을 버전 목록에서 숨깁니다. 패키지 관리자가 새 버전을 선택할 때는 가장 최신의 허용 버전을 가져오므로 업데이트가 조용히 늦춰집니다. 반면 잠금 파일이 아직 대기 중인 버전을 정확히 지정하면 npm이나 PyPI 다운로드 요청은 404로 실패합니다. 작성자는 잠금 파일을 프록시 경로에 맞춰 다시 생성하거나 대기 기간이 끝날 때까지 기다리는 방식을 안내했습니다. pub는 동작이 다릅니다. 게시 후 3일을 기다리지만 기존 pubspec.lock이 지정한 버전은 계속 내려받습니다.

이 회사는 저장소마다 최소 게시 연령 설정을 넣는 대신 프록시를 선택했습니다. 저장소 설정은 누락된 Dockerfile이나 설정을 읽지 않는 개인 노트북까지 다루지 못하지만, 회사가 관리하는 중앙 경로는 자체 호스팅 CI 실행기에도 적용됩니다. 회사 맥에는 Fleet의 자체 서비스 앱이 패키지 관리자 설정을 배포합니다. 자체 호스팅 CI는 IP로, 호스팅 CI는 서비스 토큰으로 접근하고, 직원은 Google 로그인 뒤 개인 토큰을 발급받습니다.

프록시는 다운로드마다 Google 계정이나 서비스 토큰, CI 실행 환경을 기록합니다. 문제가 발견되면 Grafana에서 해당 버전을 받은 계정을 조회할 수 있습니다. 차단 목록에는 특정 패키지 버전을 지정하며, 목록에 오른 버전은 캐시에 이미 들어 있어도 다운로드 요청에 403을 반환합니다. 프록시 자체에는 로그인 기능이 없어 별도 토큰 서비스와 Google 로그인을 앞에 둡니다.

작성자가 집계한 2026년 10월 20일부터 11월 1일까지의 운영 기록에서 프록시는 14개 계정의 다운로드 81,710건을 처리했습니다. 너무 새로워 버전 목록에서 숨긴 패키지 버전은 6,116개였으며, 이 가운데 6,049개는 npm, 67개는 pub였습니다. 잠금 파일이 대기 중인 버전을 고정해 거절된 다운로드 요청은 71건이었습니다. 작성자가 확인한 거절 사례에는 vite, rollup, swc 등 정상적으로 배포된 새 버전도 포함됐습니다. 정책의 비용은 악성 버전뿐 아니라 정상 업데이트에도 생깁니다.

프록시를 설정해도 모든 패키지 관리자가 자동으로 그 경로를 쓰지는 않습니다. 작성자는 Yarn 1의 잠금 파일에 레지스트리의 직접 URL이 들어 있으면 프록시를 건너뛸 수 있고, uv sync --frozen도 PyPI의 파일 호스트에서 직접 내려받는다고 설명했습니다. Poetry에는 레지스트리 변수가 없어 프로젝트 설정과 잠금 파일을 손봐야 합니다. Dependabot과 Renovate의 대기 기간도 프록시와 맞추지 않으면 새 버전을 제안한 업데이트 요청이 CI에서 실패할 수 있습니다.

이 설정은 게시 시점만 확인하므로 일주일 안에 발견되지 않은 악성 버전은 대기 기간이 끝난 뒤 통과합니다. 작성자는 실제 사용 중인 git-pkgs/proxy v0.10.0에서 Maven과 Go가 기본 대기 설정과 관계없이 제공되는 사례도 확인했습니다. 2일 된 Maven 버전과 5일 된 Go 모듈이 전달됐습니다. 따라서 보고된 정책은 모든 레지스트리와 잠금 파일에 일괄 적용되는 규칙이 아니라, 프록시를 통과하도록 구성된 생태계와 클라이언트에 적용되는 운영 방식입니다.

자료: brunoj.com / 정리·해설: Trawling