PyPI가 14일 지난 릴리스를 잠근다: 오래된 버전 오염을 막는 새 규칙

PyPI는 공개된 지 14일이 지난 릴리스에 새 파일을 추가하지 못하도록 제한했습니다. Python 패키지 배포 방식에 생기는 변화와 유지관리자가 준비할 점을 살펴봅니다.

PyPI가 14일 지난 릴리스를 잠근다: 오래된 버전 오염을 막는 새 규칙

Python 패키지는 하나의 버전에 소스 배포본과 운영체제·Python 버전별 wheel 파일을 여러 개 담을 수 있습니다. 과거에는 릴리스가 오래된 뒤에도 새 파일을 추가할 수 있었지만, 이제 PyPI는 공개된 지 14일이 지난 릴리스에 새 파일 업로드를 거부합니다. 이미 신뢰를 얻은 오래된 버전에 공격자가 악성 파일을 끼워 넣는 경로를 미리 닫기 위한 조치입니다.

무엇이 달라졌나

예를 들어 example-package 2.4.0을 공개한 뒤 14일이 지나면 같은 버전에 새로운 wheel이나 소스 배포본을 추가할 수 없습니다. 다른 플랫폼 지원 파일이 뒤늦게 필요하더라도 기존 버전을 다시 열어 보완하는 대신 2.4.1처럼 새 버전을 발행해야 합니다.

제한은 PyPI의 업로드 단계에서 적용됩니다. 기존에 공개된 파일을 내려받는 동작이나 새 버전을 만드는 흐름은 바뀌지 않습니다. 핵심은 오래된 릴리스가 계속 파일을 받아들이는 ‘열린 상태’로 남지 않게 하는 것입니다.

오래된 버전에 파일을 추가하는 것이 왜 위험한가

공격자가 프로젝트의 배포 토큰이나 CI 워크플로를 탈취하면 눈에 띄는 새 버전을 만드는 대신 이미 널리 사용되고 신뢰받는 버전에 특정 플랫폼용 악성 wheel을 추가할 수 있습니다. 같은 버전 번호라도 설치 시점과 운영체제에 따라 서로 다른 파일을 받게 되어, 일부 이용자만 감염되는 혼란스러운 상태가 생길 수 있습니다.

PyPI는 이 방식이 실제 공격에 악용된 사례를 현재까지 파악하지 못했다고 밝혔습니다. 이번 변경은 사고 뒤의 봉쇄가 아니라, 기술적으로 가능했던 공격 경로를 사용되기 전에 차단하는 예방 조치입니다.

14일이 선택된 배경

늦게 wheel을 추가하는 정상적인 워크플로도 있습니다. 새 Python 버전이 나온 뒤 기존 패키지 버전에 호환 wheel을 더하거나, 특정 운영체제 빌드가 늦어지는 경우입니다. PyPI 팀은 제한이 생태계에 미칠 영향을 확인하기 위해 오래된 릴리스에 파일을 추가한 프로젝트를 조사했습니다.

상위 1만 5천 개 패키지에서 Python 3.14 호환 wheel을 릴리스 14일 이후에 추가한 프로젝트는 56개였습니다. PyCon US 2026 Packaging Summit에서는 이런 경우 기존 버전에 파일을 붙이는 대신 다음 패치 버전을 발행하도록 요구하는 것이 수용 가능하다는 공감대가 형성됐습니다. 변경을 구현한 Warehouse 패치는 2026년 7월 8일 병합됐고, PyPI는 7월 22일 정책을 공식 안내했습니다.

패키지 유지관리자가 확인할 것

  • 모든 배포 파일을 한 번에 준비합니다. sdist와 Linux·macOS·Windows wheel 빌드가 완료된 뒤 같은 릴리스로 업로드되도록 CI 순서를 점검해야 합니다.
  • 지연된 플랫폼 빌드는 새 패치 버전으로 처리합니다. 14일을 넘겼다면 오래된 버전에 파일을 추가하려 하지 말고 버전을 올려 다시 배포합니다.
  • TestPyPI와 사전 검증을 활용합니다. 본 배포 전에 메타데이터, wheel 태그, 설치 테스트를 끝내면 공개 후 수정할 일을 줄일 수 있습니다.
  • Trusted Publishing을 검토합니다. 장기 보관 API 토큰 대신 OIDC 기반의 짧은 자격 증명을 사용하면 탈취 가능한 비밀값의 범위를 줄일 수 있습니다.
  • CI 업로드 권한을 최소화합니다. 빌드와 공개 단계를 분리하고 보호된 환경·승인 규칙을 적용하면 워크플로 변조가 곧바로 배포로 이어지는 위험을 낮출 수 있습니다.

사용자에게 생기는 변화

일반적인 pip install 사용자는 별도 설정을 바꿀 필요가 없습니다. 대신 하나의 오래된 버전에 나중에 파일이 추가되어 설치 결과가 달라질 가능성이 줄어듭니다. 특정 Python 버전이나 플랫폼 지원이 늦게 추가되는 프로젝트에서는 같은 기능을 가진 새 패치 버전이 더 자주 보일 수 있습니다.

잠금 파일과 해시 검증의 중요성은 그대로입니다. 14일 제한은 오래된 릴리스에 새 파일을 넣는 공격만 막습니다. 공격자가 새 버전 자체를 악성으로 배포하거나 기존 파일이 처음부터 오염된 경우에는 별도의 검토와 탐지 체계가 필요합니다.

아직 완성된 ‘닫힌 릴리스’ 표준은 아니다

PyPI는 현재 이 동작에 의존해 자동화 로직을 만들지 말라고 안내합니다. 릴리스가 새 파일을 받을 수 있는지 확인하는 표준 API와 명확한 상태 의미가 아직 정의되지 않았기 때문입니다. 업로드 도구가 받는 오류만으로 정책 상태를 추론하면 향후 구현 변화에 취약할 수 있습니다.

장기적으로는 초안 상태에서 여러 파일을 모아 검증한 뒤 한 번에 공개하는 Upload 2.0 API와 Staged Previews가 이 문제를 더 체계적으로 다룰 예정입니다. 관련 표준인 PEP 694는 아직 Draft 상태이며, 원자적 공개·병렬 업로드·상태 조회 같은 기능을 제안하고 있습니다.

배포 속도보다 릴리스의 경계를 분명하게

이번 정책의 의미는 단순히 업로드 기한을 하나 추가한 데 있지 않습니다. 한번 공개되어 신뢰가 쌓인 릴리스의 구성은 일정 시간이 지나면 더 이상 조용히 바뀌지 않아야 한다는 원칙을 강화했습니다. 유지관리자는 플랫폼별 산출물을 더 일관되게 묶어 배포해야 하고, 사용자는 같은 버전 번호가 시간이 지나며 달라지는 위험을 덜게 됩니다.

14일 잠금은 토큰 보호, 빌드 출처 증명, 해시 고정, 검토 절차를 대신하지 않습니다. 그러나 오래된 안정 버전을 악성 파일로 오염시키는 한 가지 경로를 낮은 운영 비용으로 닫는 실용적인 방어선입니다.


출처: PyPI Blog — Releases now reject new files after 14 days · PyPI Warehouse PR #19727 · PEP 694 — Upload 2.0 API · DevOps.com — GitHub and PyPI bet on time