No, installing packages with apt or dpkg does not touch pip or its certificate bundle at all — those tools download from the Ubuntu archives using the system OpenSSL library and the ca-certificates package. The real exposure lives in pip and in Python libraries that trust the certifi bundle, and you can close that gap by pointing pip and your code at the system CA store.
Why the system update is not enough
When a certificate authority is distrusted following a security incident, the fix lands in two very different places:
- The operating system trust store. On Ubuntu this is the
ca-certificatespackage, which populates/etc/ssl/certs. An ordinaryapt update && apt upgraderemoves the bad CA here, protectingapt,curl,wget, browsers, and everything that uses OpenSSL with the system store. - Python's own bundled trust store. The
certifipackage ships a static CA file inside every copy installed — and because each virtual environment installs its owncertifi, every venv carries an independently frozen snapshot of the CA list. A venv created months ago will keep trusting the revoked CA even after the OS is patched.
That split is the core of the problem. Ubuntu depends heavily on Python, and the temptation to "just upgrade pip system-wide" is dangerous: pip on the system level is managed by python3-pip and python3-certifi packages, and replacing them with versions from PyPI can break OS tooling that expects the distro's versions. The good news is you usually do not need to upgrade anything — you only need to redirect trust.
What is actually at risk, and what is not
Separate the surface area before you change anything:
- Safe:
apt install,dpkg -i, and anypython3-*package pulled from the Ubuntu repositories. These never invoke pip and never consultcertifi. - Protected already: code that uses the distro's
python3-certifipackage. Debian and Ubuntu patch it so it delegates to the system CA store rather than its bundled file. - At risk: any virtual environment that installed
certififrom PyPI, plus any library that readscertifi.where()directly — most notablyrequests, which is whatpipitself uses for HTTPS.
To audit your machines, look for copies of the bundled file:
find / -path '*/certifi/cacert.pem' 2>/dev/null
Each hit is an independent trust store to worry about. Check whether the distrusted CA's fingerprint still appears in any of them.
Fixing pip without upgrading it
pip has a built-in escape hatch: the deprecated legacy-certs mode skips the certifi store and lets you supply your own CA bundle with --cert. On Ubuntu, point it at the system file:
pip install --use-deprecated=legacy-certs \
--cert /etc/ssl/certs/ca-certificates.crt <package>
To make this permanent, edit the configuration file rather than using pip config --global set — note that passing a value like legacy-certs through pip config set under a use-deprecated key can be rejected as an invalid choice by the CLI validator even though the config file accepts it. Create ~/.config/pip/pip.conf (or /etc/pip.conf for all users) containing:
[global]
use-deprecated = legacy-certs
cert = /etc/ssl/certs/ca-certificates.crt
This does two things per the Python core maintainers: it stops pip from building its trust store from certifi, and it makes pip validate TLS against the system CA bundle that your distribution has already patched. Do not rely on a PIP_CERT environment variable for this — the setting is not reliably honored through the environment.
Be aware this fix is pip-only. It does nothing for other code in the same venv.
Protecting libraries that use certifi directly
Libraries like requests, and anything built on libcurl, consult certifi on their own. The standard mitigation is to override the relevant environment variables and monkey-patch certifi at application startup, before any network calls happen:
import os
SYSTEM_CA = "/etc/ssl/certs/ca-certificates.crt"
os.environ["REQUESTS_CA_BUNDLE"] = SYSTEM_CA
os.environ["CURL_CA_BUNDLE"] = SYSTEM_CA
try:
import certifi
certifi.where = lambda: SYSTEM_CA
except ImportError:
pass
This redirects requests to the system store, redirects anything using libcurl defaults, and rewrites certifi's path lookup so every other consumer in the process also gets the patched bundle. Place it as early as possible in your entry point.
Verification and prevention
After applying the changes, confirm pip is using the system bundle:
pip config debug
pip install --dry-run --use-deprecated=legacy-certs \
--cert /etc/ssl/certs/ca-certificates.crt requests
Longer term:
- Recreate venvs regularly so their
certificopies refresh, and prefer systempython3-certifiwhere possible. - Keep
ca-certificatescurrent via unattended upgrades; it is the anchor for everything above. - Treat bundled CA files (
certifi, Go binaries, Node, Rust programs withwebpki-roots) as independent trust stores that each need their own incident response. - For high-value downloads, verify hashes or signatures out of band; TLS alone is only as strong as the trust store behind it.
Frequently Asked Questions
Does apt install use pip's certificates?
No. apt and dpkg use OpenSSL with the system ca-certificates bundle and download prebuilt packages from the Ubuntu archives. pip is never involved.
Is the distro's python3-certifi package safe?
Yes. Debian and Ubuntu build it so it references the system CA store, so updating ca-certificates updates it too. Only venv-installed certifi carries its own frozen bundle.
Why did my pip config --global set command fail with "invalid choice"?
The CLI validates use-deprecated against its other known values and may reject legacy-certs passed that way. Write the settings directly into pip.conf instead — the file accepts the combination fine.
Can I just upgrade pip in each venv instead?
You can — a newer pip with an updated certifi also resolves the issue — but for system pip on Ubuntu, upgrading out of the distro's packages risks breaking OS tooling. Redirecting to the system CA store achieves the same protection with no version changes.
Does the monkey-patch cover every Python library?
It covers requests, libcurl-based clients, and anything that calls certifi.where(). Libraries that open raw SSL sockets and hardcode their own trust handling may need explicit ssl.create_default_context(cafile=...) configuration.
Should I pin the new pip.conf in CI as well?
Yes. CI runners frequently create fresh venvs with old cached certifi copies, so applying the same pip configuration and environment overrides there closes the same gap.