PyPI Publishing Security Guide: AI-Optimized Reference
Critical Context & Threat Landscape
Current State: Malicious package attacks increased 200% in 2025. PyPI faces thousands of malicious packages uploaded monthly. Supply chain attacks are now standard threat vectors.
Major Incidents: December 2024 Ultralytics breach - Bitcoin mining malware injected into popular computer vision package through compromised GitHub Actions workflow.
Authentication & Access Control
API Token Issues
Problem: Legacy passwords disabled in 2024. Common failure: "HTTP 403: Invalid or non-existent authentication information"
Solution:
twine upload dist/* --username __token__ --password pypi-your-actual-token-here
Storage Configuration (~/.pypirc
):
[pypi]
username = __token__
password = pypi-AgEIcHlwaS5vcmcyLongTokenStringHere
Trusted Publishing (Recommended)
Security Level: Eliminates token storage completely
Implementation Time: 5 minutes setup
Authentication Method: GitHub Actions OIDC with PyPI
Setup Process:
PyPI: Account Settings → Publishing → Add pending publisher
- Repository:
username/package
- Workflow:
publish.yml
- Environment:
pypi
- Repository:
GitHub: Create protected environment
pypi
- Settings → Environments → New environment
- Required reviewers (access control)
- Prevents unauthorized publishing
Workflow Configuration:
name: Publish to PyPI
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Build package
run: |
pip install build
python -m build
- uses: pypa/gh-action-pypi-publish@release/v1
Package Structure & Configuration
Modern Package Layout (src/ layout)
Critical Advantage: Prevents testing local code instead of installed package
Failure Prevention: Catches import errors before users encounter them
Structure:
myproject/
├── src/
│ └── mypackage/
│ ├── __init__.py
│ └── core.py
├── tests/
├── pyproject.toml
└── README.md
pyproject.toml Configuration
Status: setup.py
is deprecated. pyproject.toml
is the only modern standard.
Working Configuration:
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mypackage"
version = "0.1.0"
description = "Does stuff without breaking"
authors = [{name = "Your Name", email = "you@domain.com"}]
license = {text = "MIT"}
dependencies = [
"requests>=2.31.0,<3.0.0", # Pin major versions
"click>=8.0.0"
]
requires-python = ">=3.8"
[tool.setuptools.packages.find]
where = ["src"] # Critical for src layout
Common Failure: Missing build-backend
and where
configuration causes module import failures.
Security Scanning & Vulnerability Management
Dependency Vulnerabilities
Primary Attack Vector: Most common compromise method
Scanning Tools:
pip install pip-audit
pip-audit # Scans against PyPA Advisory Database
pip-audit --desc # Shows vulnerability descriptions
pip-audit --fix # Attempts to upgrade to safe versions
Workflow Security
Tool: zizmor
- detects template injection attacks
pip install zizmor
zizmor .github/workflows/
CI Integration:
- name: Audit dependencies
run: pip-audit --desc --format=json
- name: Audit workflows
run: zizmor --format=json .github/workflows/
Version Management & Compatibility
Semantic Versioning Requirements:
1.0.0
→1.0.1
: Bug fixes (safe auto-update)1.0.0
→1.1.0
: New features (probably safe)1.0.0
→2.0.0
: Breaking changes (requires human review)
Automation:
pip install bump2version
bump2version patch # 1.0.0 → 1.0.1
bump2version minor # 1.0.1 → 1.1.0
bump2version major # 1.1.0 → 2.0.0
Testing & Quality Assurance
Installation Testing
Critical Step: Test installed package, not local code
# Build and install in isolated environment
python -m build
pip install dist/*.whl --force-reinstall
# Verify installation
python -c "import mypackage; print(mypackage.__version__)"
python -m pytest tests/
Common Hidden Failures:
- Missing
__init__.py
files - Incorrect package paths in
pyproject.toml
- Missing data files not included in MANIFEST.in
- Import errors from incorrect module structure
Multi-Version Testing
Tool: tox
for comprehensive Python version testing
# tox.ini
[tox]
envlist = py38,py39,py310,py311
[testenv]
deps = pytest
commands = pytest tests/
GitHub Actions Matrix:
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
Dependency Management
Conflict Resolution
Diagnostic Tool:
pip install pipdeptree
pipdeptree --warn conflict
Best Practices:
- Loose pinning:
requests>=2.28.0,<3.0.0
- Avoid exact pinning (
==
) unless specific reason - Use dependency groups:
[project.optional-dependencies]
Cross-Platform Compatibility
Tool: cibuildwheel
for universal wheels
Critical for: C extensions, Apple Silicon compatibility
# .github/workflows/wheels.yml
- name: Build wheels
uses: pypa/cibuildwheel@v2.16.2
env:
CIBW_ARCHS_MACOS: x86_64 arm64 # Both Intel and M1
CIBW_ARCHS_LINUX: x86_64 aarch64 # Both x64 and ARM
Release Process & Human Controls
Staging Workflow
Required Step: Test on TestPyPI before production
# Upload to TestPyPI
twine upload --repository testpypi dist/*
# Test installation
pip install --index-url https://test.pypi.org/simple/ mypackage
# Production upload only after verification
twine upload dist/*
Human Firewall Requirements
- Code review: All changes require PR approval
- Protected environments: Only trusted maintainers can publish
- Release checklist: Documented manual verification steps
- Fresh environment testing: Test wheel installation on clean Python environment
Threat Response & Incident Management
Credential Compromise
Timeline: Leaked credentials get scraped within minutes
Response Protocol:
- Immediately revoke leaked credentials
- Delete PyPI release (30-minute window before permanent caching)
- Generate new credentials
- Add leaked keys to
.gitignore
, use environment variables - Consider compromised systems breached until proven otherwise
Typosquatting Protection
Monitoring:
- Register common typos early
- Use PyPI-Scout for similar name monitoring
- Set up Google Alerts for package name
Response: File PyPI support request immediately with evidence
Package Abandonment
Requirements: Either transfer ownership or mark deprecated
Reason: Abandoned packages become attack targets
Production Package Considerations
High-Impact Package Responsibilities
Indicators:
- Major company dependencies (check Libraries.io)
- High download statistics (
pypistats
) - GitHub "Used by" tab shows critical projects
Additional Requirements:
- More rigorous testing procedures
- Security-focused development practices
- Communication channels for security issues
- Succession planning (bus factor > 1)
Corporate Security Compliance
Common Flags:
- Network requests
- File system access
- Dependencies with CVEs
- Unknown publisher
Documentation Template:
## Security Information
This package:
- ✅ Makes HTTPS requests to api.example.com only
- ✅ Reads/writes files only in user-specified directories
- ✅ Dependencies scanned with pip-audit (see CI results)
- ✅ Published via GitHub Actions with signed commits
- ❌ Does NOT access sensitive system resources
- ❌ Does NOT make unexpected network connections
Deprecation Management
Breaking Change Timeline
- Version 1.5.0: Add deprecation warnings
- Version 1.6.0: Increase warnings, update documentation
- Version 2.0.0: Remove deprecated features
Implementation:
import warnings
def old_function():
warnings.warn(
"old_function() is deprecated, use new_function() instead. "
"This will be removed in version 2.0.0",
DeprecationWarning,
stacklevel=2
)
return new_function()
Minimum Timeline: 3 months and 2 minor versions for migration
Publishing Method Comparison
Method | Security Risk | Maintenance Burden | Best Use Case | Critical Weakness |
---|---|---|---|---|
Manual twine | Token storage vulnerability | High - constant token rotation | Learning/one-offs | Human error prone |
GitHub Actions (token) | Secret leakage risk | Medium - token management | Legacy workflows | Token compromise |
Trusted Publishing | Minimal - no stored secrets | Low - automatic auth | Production packages | Requires GitHub/PyPI setup |
Local build | High - dev machine compromise | Very high - bus factor of 1 | Emergency fixes only | Single point of failure |
Essential Toolchain
Security Tools
pip-audit
: PyPA Advisory Database scanningzizmor
: GitHub Actions security analysissafety
: Commercial vulnerability databasebandit
: Python code security analysis
Build Tools
build
: Modern package builder (replaces setup.py)cibuildwheel
: Multi-platform wheel buildingtwine
: Package uploading
Testing Tools
tox
: Multi-version Python testingpytest
: Test frameworkpipdeptree
: Dependency conflict analysis
Monitoring Tools
pypistats
: Download analytics- Libraries.io: Reverse dependency tracking
- PyPI-Scout: Typosquatting monitoring
Resource References
Critical Resources
- PyPI Help: Official troubleshooting
- Trusted Publishing Guide: Token-free publishing
- PyPI Support: Malicious package reporting
- Python Infrastructure Status: Service availability
Security Resources
- PyPI Blog: Security announcements
- Python Vulnerability Database: Known vulnerabilities
- Sonatype Security Research: Malicious package analysis
Development Resources
- PyPA Sample Project: Reference implementation
- pyOpenSci Packaging Guide: Modern best practices
- TestPyPI: Staging environment
Useful Links for Further Investigation
Essential Resources for Package Publishing
Link | Description |
---|---|
PyPI Help & FAQ | Official troubleshooting when shit breaks |
Python Packaging User Guide | The canonical reference, not always up to date |
Trusted Publishing Guide | How to publish without storing tokens |
PyPI Terms of Use | Legal requirements for package publishing |
pip-audit | Scan dependencies for known vulnerabilities |
zizmor | Find GitHub Actions security issues |
safety | Alternative vulnerability scanner with commercial DB |
Bandit | Find security issues in your Python code |
build | Modern package builder, replaces `setup.py` |
cibuildwheel | Build wheels for all platforms automatically |
PyPI Support | Report malicious packages, security issues, account problems |
Stack Overflow pypi tag | Where you'll be debugging at 3am |
Python Infrastructure Status | Check if PyPI is down before panicking |
GitHub Actions PyPI Publish | Official action for Trusted Publishing |
Pre-commit hooks | Catch issues before they hit CI |
tox | Test your package across Python versions |
nox | More flexible alternative to tox |
PyPA GitHub Organization | Where Python packaging tools are developed |
pyOpenSci Packaging Guide | Comprehensive guide with modern best practices |
PyPI Blog | Security announcements and policy changes |
Sonatype Security Research | Reports on malicious package campaigns |
Checkmarx Supply Chain Security | Analysis of package repository attacks |
TestPyPI | Staging environment for testing uploads |
pypistats | Download statistics and usage analytics |
Libraries.io | See what depends on your package |
Snyk Advisor | Package health and security scores |
PyPA Sample Project | Reference implementation of modern packaging |
Python Package Template | Cookiecutter with CI/CD setup |
Hypermodern Python | Best practices guide with working examples |
MITRE CVE Database | Check if vulnerabilities have CVE numbers assigned |
Python Vulnerability Database | Browse known security vulnerabilities in Python packages |
PyPI Security Reporting | Guidelines for reporting security issues |
Related Tools & Recommendations
Uv vs Pip vs Poetry vs Pipenv - Which One Won't Make You Hate Your Life
I spent 6 months dealing with all four of these tools. Here's which ones actually work.
Python Dependency Hell - Now With Extra Steps
pip installs random shit, virtualenv breaks randomly, requirements.txt lies to you. Pipenv combines all three tools into one slower tool.
Stop Conda From Ruining Your Life
I wasted 6 months debugging conda's bullshit so you don't have to
GitHub Actions + Jenkins Security Integration
When Security Wants Scans But Your Pipeline Lives in Jenkins Hell
uv - Python Package Manager That Actually Works
Discover uv, the high-performance Python package manager. This overview details its core functionality, compares it to pip and Poetry, and shares real-world usa
PyPI - Where Python Packages Live
The place your pip install goes to grab stuff, hosting 665k+ packages that mostly work
I've Been Testing uv vs pip vs Poetry - Here's What Actually Happens
TL;DR: uv is fast as fuck, Poetry's great for packages, pip still sucks
uv Performance Optimization and Troubleshooting
uv is fast as hell until it eats all your RAM and crashes your Docker builds. Here's how to tame it.
Crates.io - Where Rust Packages Live
The official Rust package registry that works with cargo add and doesn't randomly break your builds like npm
How We Stopped Breaking Production Every Week
Multi-Account DevOps with Terraform and GitOps - What Actually Works
Stop MLflow from Murdering Your Database Every Time Someone Logs an Experiment
Deploy MLflow tracking that survives more than one data scientist
Conda - когда pip снова все сломал
Пакетный менеджер, который реально работает в production
Conda - The Package Manager That Actually Solves Dependency Hell
Stop compiling shit from source and wrestling with Python versions - conda handles the messy bits so you don't have to
Poetry — dependency manager для Python, который не врёт
Забудь про requirements.txt, который никогда не работает как надо, и virtualenv, который ты постоянно забываешь активировать
uv Docker Production Deployment - Troubleshooting & Best Practices
integrates with uv
GitHub Actions is Fine for Open Source Projects, But Try Explaining to an Auditor Why Your CI/CD Platform Was Built for Hobby Projects
integrates with GitHub Actions
GitHub Actions + Docker + ECS: Stop SSH-ing Into Servers Like It's 2015
Deploy your app without losing your mind or your weekend
Pip - Python's Package Installer That Usually Works
Install Python packages from PyPI. Works great until dependencies conflict, then you'll question your career choices.
Anaconda AI Platform - Enterprise Python Environment That Actually Works
When conda conflicts drive you insane and your company has 200+ employees, this is what you pay for
uv Advanced Configuration for Enterprise Environments
Corporate networks fucking hate uv. Here's how to make it work anyway.
Recommendations combine user behavior, content similarity, research intelligence, and SEO optimization