Skip to content

Docker default vs hardened: the container isolation score gap, measured

"Harden your containers" is advice everyone repeats and almost nobody quantifies. How much isolation does hardening actually buy you? We put a number on it.

We ran ironctl scan over 151 of the most-pulled public Docker images twice: once on the exact docker run defaults their own READMEs tell you to use, and once with a standard hardening stanza applied. The scan grades seven containment dimensions 0 to 100.

The gap is not subtle.

Configuration Average score Grade range
Default docker run 52 D to C (48 to 63)
Hardened docker run 100 A (every image)

On defaults, not one of the 151 images reaches an A. Scores run from 48 to 63. Hardened, all 151 land on a clean 100. The full leaderboard on defaults is here; the delta below is what hardening adds on top.

The six flags that carry the grade

Here is the hardened command the scan grades. It is base-image agnostic; it scores 100 whether the last argument is alpine, debian, node, or postgres:

docker run -d \
  --user 65532:65532 \
  --cap-drop=ALL \
  --security-opt=no-new-privileges \
  --read-only --tmpfs /tmp \
  --network=none \
  your-image:tag

Dimension by dimension: where the 48 points come from

Take a typical default-configured image at 48 out of 100 and watch each flag close a specific hole:

Dimension Default Hardened Flag that closes it Max
Non-root user 0 15 --user 65532:65532 15
Dropped capabilities 4 20 --cap-drop=ALL 20
Read-only root filesystem 0 10 --read-only --tmpfs /tmp 10
Network isolation / egress 4 15 --network=none 15
Seccomp profile 15 15 already on by default 15
No docker.sock exposure 15 15 do not mount the socket 15
No shared host namespaces 10 10 do not share host namespaces 10
Total 48 100 100

Four dimensions do the work. Docker's default seccomp profile already earns full marks, and most images do not mount the docker socket or share host namespaces, so those three are usually green before you touch anything. The points you are leaving on the table are the first four: root user, full capabilities, writable filesystem, and open egress.

What separates a C from a D on defaults

The only reason any default image scores above 48 is that it already dropped one of those habits. The images at the top of the leaderboard, at 63 out of 100, are the ones whose image sets a non-root user in the Dockerfile. That single choice is worth 15 points:

Dimension alpine (48, D) adminer (63, C)
Non-root user 0 15
every other dimension same same

That is the whole difference between the best and worst default scores in a 151-image survey: one dimension. Which is the point. Isolation on defaults is a narrow band because almost every image makes the same four omissions.

The catch hardening does not fix

Every flag above is real, worthwhile hardening, and it takes you from a D to an A on the config scan. But the scan grades configuration posture, and there is one thing configuration cannot change: a hardened container still shares the host kernel. When we ran a live escape suite, hardening a container blocked 4 of 5 escape attempts, up from 2 of 5 on raw defaults. The one it never blocks is the kernel-sharing attempt. Closing that last gap needs a different runtime, not a different flag. That is a separate decision, covered in gVisor vs runc.

For the config layer, though, the math is clean: six flags, +48 points, D to A, on every image we tested.

Scan and fix your own images

Every scorecard names the exact flags for that image, and ironctl scan --fix writes the hardened stanza for you. Browse the full interactive ranking and grab a score badge for your repo at the Container Isolation Scores explorer.

ironctl scan your-image:tag        # see your default score
ironctl scan your-image:tag --fix  # get the hardened command