Security Concepts

Is the Python Docker Image Safe? What Our Scanner Found

Published July 14, 2026 · 6 min read

Python is a default choice for data pipelines and backend services alike, so “is the python Docker image safe” matters before you build on it. We scanned python:3.12 and its Alpine variant with ScanRook to see what a 31,590-finding scan result actually means in practice.

Is the python Docker image safe — container image safety series

The verdict

Mostly yes, but not on the default tag for production. python:3.12 ships a complete Debian build environment so pip can compile C extensions from source, and that toolchain accounts for nearly all of the 31,590 findings in our scan — not CPython itself. The fix mirrors what we recommend for other language runtimes in this series: build with the full tag if you need the compiler, then ship on python:3.12-alpine or a slim/distroless runtime that never carried the build tooling in the first place.

What we found scanning python:3.12

We exported the image with docker save and scanned it with ScanRook, which matches every installed package against OSV, NVD, and vendor advisory data:

TagTotalCriticalHighMediumLow
python:3.1231,5901,8759,21317,5141,115
python:3.12-alpine4043817917410

ScanRook v1.14.2, warm-cache scan, 2026-07-04. Counts change as new advisories publish.

Grouped bar chart of ScanRook severity counts. python:3.12: 31,590 findings total, 1,875 critical, 9,213 high, 17,514 medium, 1,115 low. python:3.12-alpine: 404 findings total, 38 critical, 179 high, 174 medium, 10 low.python:3.1231,590 findings totalCritical1,875High9,213Medium17,514Low1,115python:3.12-alpine404 findings totalCritical38High179Medium174Low10
The same scan data as a chart — ScanRook v1.14.2 warm-cache scan of python:3.12 and python:3.12-alpine, 2026-07-04. Bar length is proportional to the count in each severity bucket, on a scale shared by both tags; the figure beside each tag name is the total finding count that scan reported.

That is about a 99% drop between tags for the same Python version, nearly identical to what we found scanning the Node.js image in this series. Both runtimes ship a full Debian build toolchain by default for the same reason: compiling native extensions on install.

The CVEs worth knowing about

The top critical findings in python:3.12 sit in build-tooling packages, not in CPython:

  • dirmngr — CVE-2005-2023 and CVE-2006-6235.GnuPG's key-fetching helper, present for Debian's package-verification chain. It has no role in a running Python process.
  • file — CVE-2004-1304. The Unix file command used to detect binary formats during builds. A two-decade-old advisory against a utility application code never invokes.
  • gnupg — CVE-2005-2023 and CVE-2006-6235. The core GnuPG binary backing dirmngr, present for the same build-time verification purpose.

This is the same pattern that shows up across every Debian-based language runtime image: build-toolchain findings that inflate the count without reflecting risk in the running application. Our guide to installed-state scanning vs. advisory matching explains why scanners still report them.

Which tag should you use?

Use python:3.12 only as a build stage if you need to compile C extensions, and ship on python:3.12-alpine for production. A multi-stage Dockerfile installs dependencies in the full image, then copies the installed site-packages into the slim runtime stage.

If a dependency doesn't publish musl-compatible wheels and building from source under Alpine is impractical, python:3.12-slim is the middle ground — it trims most of the build toolchain while staying on glibc. Benchmark your dependency install under both before committing; see our scanner comparison notes for how we approach that kind of tradeoff analysis.

Hardening checklist

  • Use a multi-stage Dockerfile so compilers never reach your runtime image.
  • Install with pip install --no-cache-dir to avoid leaving wheel caches in image layers.
  • Run the container as a dedicated non-root user rather than the default root.
  • Pin the image by digest (python@sha256:…) so builds are reproducible.
  • Pin dependency versions in a lockfile (requirements.txt with hashes, or Poetry/uv lockfiles).
  • Rebuild and redeploy on a schedule so runtime image patches actually reach you.
  • Scan every build in CI so a base image regression is caught before it ships.

Scan it yourself

Counts drift as new advisories publish, so verify against the exact tag and digest you deploy:

curl -fsSL https://scanrook.io/install.sh | sh
docker save python:3.12 -o python.tar
scanrook scan python.tar

The full CLI reference, including JSON output and severity gating for CI, is in the docs.

Frequently asked questions

Is the python Docker image safe to use?

Mostly, but not the default tag for production. python:3.12 bundles a Debian build toolchain; python:3.12-alpine cuts findings by about 99% for the same version.

Why does python:3.12 have so many vulnerabilities?

It ships compiler tooling and package-verification utilities so pip can build C extensions from source. Each of those packages carries its own advisory history.

Is python:alpine more secure?

Yes: 404 findings vs 31,590 in our scan, about 99% fewer, because Alpine never shipped the build toolchain to begin with.

Should I use python-slim instead?

It's a middle ground if Alpine causes wheel-compatibility issues — fewer findings than the full image, but still on glibc for compatibility.

Scan your python image with ScanRook

Upload your image tar or scan from the CLI and ScanRook matches every installed package against OSV, NVD, and vendor advisory data — with severity, exploit-probability, and confidence tiers so you can separate real runtime risk from build-time noise.

Related Posts

More on this topic.