Check your requirements.txt for vulnerabilities
== is checked against OSV.dev and PyPI, with the version that fixes all of its advisories and which ones attackers exploit today.Checked against OSV.dev, CISA KEV, FIRST EPSS, npm, PyPI, deps.dev, endoflife.date and Docker Hub, live.
Sample: A Django app’s requirements.txt
A Django app’s requirements, pinned the way pip freeze writes them. It runs on a Django line that’s past end of life, with advisories across the web server, HTTP, imaging, templating and crypto packages.
# Pinned with pip freeze django==3.2.12 gunicorn==20.0.4 requests==2.25.1 urllib3==1.26.4 pillow==9.0.0 jinja2==2.11.2 pyyaml==5.3.1 cryptography==3.3.2
9 findings: 7 critical and 2 warnings
8 packages from requirements.txt
Critical: 23 known vulnerabilities in pillow 9.0.0
requirements.txt12.3.0CVE-2023-4863 exploited in the wild (CISA)
Critical: 27 known vulnerabilities in django 3.2.12
requirements.txt5.2.17
Critical: 13 known vulnerabilities in cryptography 3.3.2
requirements.txt48.0.1
Critical: CVE-2020-14343 in pyyaml 5.3.1
requirements.txt5.4
Critical: 11 known vulnerabilities in urllib3 1.26.4
requirements.txt2.8.0
Critical: 2 known vulnerabilities in gunicorn 20.0.4
requirements.txt22.0.0
And 3 more findings in the full result.
Last checked against GitHub, OSV.dev, deps.dev, CISA KEV, FIRST EPSS, PyPI and endoflife.date.
What it reads in requirements.txt
- Lines pinned with
==or===, with extras and environment markers allowed:uvicorn[standard]==0.30.0,pywin32==306 ; sys_platform == "win32". - Every
requirements*.txtfile you drop. Names containing dev, test, lint or doc count as development dependencies. .python-versionor.tool-versions, so an end-of-life Python shows up next to your packages.- A Django pin also gets Django’s support status from endoflife.date, with the LTS line to move to.
Why exact pins matter here
Unlike a lockfile, requirements.txt can hold anything from exact pins to open ranges, and pip resolves ranges when it installs. A checker that only reads the file can’t know what requests>=2.25 became on your machine, so this one checks what is pinned and skips the rest instead of reporting advisories for a version you might not have.
If your file has ranges, check the environment instead: run pip freeze where the app runs and paste the output. If you use pyproject.toml with uv or Poetry, the pyproject.toml checker reads your lockfile.
How it compares with pip-audit
| Tool | What it reads and checks | Use it when |
|---|---|---|
| pip-audit | Python environments, requirements files and pyproject.toml. With -r it does its own dependency resolution, much like pip install, so it finds transitive packages. It uses the PyPI vulnerability data by default, OSV optionally, and --fix can upgrade for you. | You can run it in the project or in CI, and want every resolved dependency covered. |
| This check | The pins in the file you paste, with no install or resolution. Adds CISA KEV and EPSS ranking, Django and Python end of life, deprecated or archived PyPI projects, and npm, Go, Rust and Docker files in the same check. | You want an answer without setting up a Python environment, or a ranked task to hand to your coding agent. |
Python environments, requirements files and pyproject.toml. With -r it does its own dependency resolution, much like pip install, so it finds transitive packages. It uses the PyPI vulnerability data by default, OSV optionally, and --fix can upgrade for you.
Use it when: You can run it in the project or in CI, and want every resolved dependency covered.
This check
The pins in the file you paste, with no install or resolution. Adds CISA KEV and EPSS ranking, Django and Python end of life, deprecated or archived PyPI projects, and npm, Go, Rust and Docker files in the same check.
Use it when: You want an answer without setting up a Python environment, or a ranked task to hand to your coding agent.
Questions
Why were some lines skipped?
Only lines that pin one version are checked: django==4.2.11. A range such as django>=4.2 doesn’t say which version pip installed, so it’s skipped rather than guessed. So are -r and -e lines, URLs and VCS links; drop an included file separately.
Does it check transitive dependencies?
It checks every pinned line in the file. A requirements.txt written by pip freeze or pip-compile already lists every installed package, so paste that for full coverage. A hand-written one only names your direct dependencies.
Can I paste pip freeze output from a server?
Yes. pip freeze prints exactly this format, so it’s the quickest way to check what a running environment has installed.
What are PYSEC and GHSA ids?
Advisory ids. PYSEC ids come from the Python Packaging Advisory Database, GHSA ids from the GitHub Advisory Database. OSV.dev collects both, and the same flaw listed under both is shown once.
Are requirements-dev.txt files treated differently?
Yes. Files with dev, test, lint or doc in the name count as development dependencies, so their findings rank one level lower unless CISA lists the advisory as exploited.
Go further than one check
Map your repo into an architecture diagram with live health on every part, get an alert when a new critical finding lands, and hand your coding agent a brief to build from. Free to start.