How to Audit Python Imports for Security Risks
Learn a step-by-step process to audit your Python dependencies for known vulnerabilities, typosquatting, and suspicious behavior, using tools like pip-audit and safety.
If you've been writing Python for any length of time, you know how easy it is to get reckless with import. Type pip install on a package that looks interesting, and suddenly you're pulling in dozens of dependencies you've never even glanced at. I've been there too, and trust me, it's a fast track to security headaches.
The reality is simple: when you import a Python package, you're running code that someone else wrote. That code could be malicious, outdated, or contain vulnerabilities. With supply chain attacks becoming more common, you really can't afford to open the door blindly.
So here's how to audit your Python imports for security risks, step by step.
Start with a full dependency inventory
Before you can check for risks, you need to know what you're actually importing. Python doesn't make this obvious because dependencies can be nested three or four layers deep.
Run this in your project root to see everything you're pulling:
pip list --format=columns
Or if you're using a requirements.txt file:
pip install -r requirements.txt -t /tmp/check_imports && pip list --path /tmp/check_imports
At PythonSkillset, we've seen projects that looked like they only had ten dependencies but ended up pulling in 47 packages through transitive dependencies. You need to see the full tree, not just the top layer.
Check for known vulnerabilities
The quickest win is to use automated vulnerability scanning tools. These compare your installed packages against public vulnerability databases like the National Vulnerability Database.
My go-to tool is pip-audit:
pip install pip-audit
pip-audit
This scans all your installed packages and tells you exactly which ones have known vulnerabilities, along with the CVE numbers and severity levels. If it finds something marked "CRITICAL," drop everything and fix it.
Another option is safety:
pip install safety
safety check
Both tools are free and run in seconds. There's really no excuse not to use them.
Verify package authenticity
Here's a trick most Python developers overlook: checking the source of your packages. When you pip install a package, it comes from PyPI, sure. But is it actually the package you think it is?
Typosquatting is real. Someone publishes "requsts" instead of "requests," and if you've had too much coffee, you might install the fake one. The fake package could contain malware that steals environment variables, SSH keys, or AWS credentials.
To check if a package is authentic:
- Verify the maintainer's identity. Look at the PyPI page for a verified publisher badge.
- Check the package's source repository. Is it on GitHub or GitLab? Does it have real commits from real people?
- Look at download statistics. Legitimate packages usually have thousands or millions of downloads. A brand-new package with zero downloads is suspicious.
You can use pip show to get details:
pip show numpy
This shows the Home-page, Author, and License fields. If any of these look fishy, dig deeper.
Review import behavior
Some packages only reveal their real behavior when they're imported. This is why you should never ignore what happens when you run import some_package.
Run your code in an isolated environment first. Use a virtual environment, Docker container, or sandbox. Then monitor for:
- Network connections you weren't expecting
- File writes to unusual locations
- Environment variable access
- Attempts to execute shell commands
You can use tools like strace (Linux) or Process Monitor (Windows) to watch all system calls. Or use the built-in audit module if you want something more lightweight:
import sys
import audit
def audit_hook(event, args):
if event in ("import", "open", "exec"):
print(f"Audit: {event} - {args}")
sys.addaudithook(audit_hook)
Now every time Python performs a security-sensitive operation, you'll see it.
Pin your dependencies
An audit is useless if your dependencies can change underneath you. If you're using requirements.txt without pinned versions, you're trusting that the latest version is safe. It usually is, but one malicious update can wreck your entire project.
Pin every single version:
requests==2.31.0
numpy==1.24.3
pandas==2.0.1
Better yet, use a lockfile like pipenv or poetry does. That way you know exactly what's installed.
Regularly audit your supply chain
Security isn't a one-time thing. Packages get compromised. New vulnerabilities are discovered daily. A package that was safe last month might be dangerous today.
Make auditing part of your workflow:
- Run
pip-auditbefore every deployment - Subscribe to security advisories for your key dependencies
- Set up automated scanning in your CI/CD pipeline
At PythonSkillset, we've found that the real danger isn't the well-known packages like Flask or Django. It's the little helper packages nobody's heard of that do something simple like parse a CSV. These packages often have a single maintainer who might disappear tomorrow.
What to do when you find a risk
If your audit turns up something suspicious, don't panic. Here's your action plan:
- Isolate the issue. Don't delete the package yet. First, understand exactly what it does.
- Check if there's a fix. A newer version might have patched the vulnerability.
- Replace the dependency. Find an alternative that does the same thing but is better maintained.
- Remove unused imports. Sometimes the risk is from a package you don't even use.
Remember, you can always rewrite the functionality yourself if the dependency is too risky. A hundred lines of your own code is better than ten lines from a malicious package.
The bottom line
Auditing Python imports isn't hard. It takes maybe ten minutes to run the tools I've described. But it can save you from a catastrophic breach, a data leak, or a ransomware attack.
Trust me, your future self will thank you.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.