A prefab bank with the master key inside
Watch it happen
A prefab bank is built from changing materials with the master key inside and all staff running as owner. Mallory breaks in through one bug and takes the key and the vault.
Mallory walks in like any visitor. The bank she enters is a prefab building, delivered from a factory.
Mallory says: Nice new building.In bank terms and app terms
| In the bank | In your app |
|---|---|
Are you exposed?
Your Dockerfile has no USER line, or starts FROM something:latest. You use COPY . . or ENV PASSWORD=… so secrets and .env files end up inside the image. Your images or compose file expose database ports or use privileged: true.
Pin the base image (node:24.22.1-alpine) and add a non-root USER before CMD. Keep secrets out of the image: pass them at runtime and add a .dockerignore for .env and .git. Deleting a secret in a later step does not remove it from earlier layers, so rotate any that were baked in. Run the database as its own service, and publish only the app’s port.
It has happened to real companies
Tesla (2018) — Researchers at RedLock found a Kubernetes dashboard on Tesla's AWS account with no password. It exposed AWS credentials, and attackers had used it to run cryptocurrency mining.
Alpine Linux Docker images CVE-2019-5021 (2019) — Official Alpine Linux Docker images from v3.3 onward shipped with a NULL password for the root user, a regression introduced in December 2015. Systems built on them that use PAM or the shadow file for authentication could accept a blank root password.
What it looks like in code
# BAD: Every common mistake
FROM node:latest # Unpinned
WORKDIR /app
COPY . . # Copies .env, secrets, node_modules
COPY .env .env # Explicit secret copy
RUN npm install
EXPOSE 3000
EXPOSE 5432 # Database in same container?
CMD ["npm", "start"] # Runs as root, no healthcheck
Ask your AI tool to fix it
Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.
Review every Dockerfile and docker-compose file. Pin base images to an exact version instead of latest, add a non-root USER, remove any secrets from ENV, COPY or ADD (read them at runtime instead), add a .dockerignore covering .env and .git, use multi-stage builds so build tools and build-time secrets never reach the final image, remove EXPOSE and published ports for databases, and never use privileged: true. Tell me which secrets were exposed so I can rotate them. Explain each change briefly.Where this comes from
The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.
- Building best practicesDockerpin base image versions, use a non-root USER, multi-stage builds
- Build secretsDockerENV and build args persist in the image; use secret mounts instead
- Docker Security Cheat SheetOWASPnever run containers with --privileged; run unprivileged; keep secrets out
- Node official image tagsDocker Hubnode:24.22.1-alpine style exact tags exist (24.22.1, 24.22, lts)
- CVE-2019-5021: NULL root password in Alpine Docker imagesTenableAlpine images from v3.3 (Dec 2015) shipped a NULL root password
- Tesla cloud resources hacked to run cryptocurrency-mining malwareArs TechnicaRedLock found Tesla's Kubernetes console without password; credentials exposed; mining
Spot a mistake or something out of date? Report a correction · How these guides are made and checked
The free, open-source scanner checks for most of the problems in these guides.