← Back to Docker Build Secrets Check
Skimming a Dockerfile for an obvious ARG DB_PASSWORD=hunter2 genuinely works, and it
is the method most people already use. This page names no product or company being compared
against: "reading the Dockerfile by hand" is a generic manual habit, not a competing tool.
| Case | Reading the Dockerfile by hand | This tool |
|---|---|---|
A literal secret-looking default, ARG DB_PASSWORD=hunter2 | Correctly caught by a reviewer who knows to look for it | Correctly caught the same way, as arg-literal |
An ENV value resolved from a build argument, ENV API_KEY=$API_KEY | No literal secret text on the line to react to -- easy to read as clean | Flags the ENV variable's name against a secret-pattern list regardless of where its value comes from |
A bare ARG SIGNING_TOKEN with no default at all | Reads as the safe version of the pattern already being watched for -- no value is visible to object to | Flags it as an advisory-only arg-declared finding, since it still invites an unsafe --build-arg |
A COPY .env /app/.env among a dozen ordinary COPY lines | Easy to miss without checking every source path against a credential-filename list | Checks every COPY/ADD source's basename and path against that fixed list every time |
| Checking every Dockerfile in a repository on every dependency-bump PR | Manual, and the first thing skipped under time pressure | CLI scans a whole checkout in one pass; --fail-on-risk blocks CI |
ENV TOKEN=$TOKEN and a bare ARG SIGNING_TOKEN both carry no secret-shaped
string anywhere in the Dockerfile for a reviewer to react to -- there is nothing that looks wrong on
the line itself. But per Docker's own "Build secrets" documentation, an ENV instruction's
resolved value is written into the image's config layer regardless of where that value came from, and
a bare ARG still invites a caller to pass a secret with --build-arg, which
BuildKit records for the build unless it is mounted as a build secret instead. This tool checks the
instruction and the variable's name, not whether a literal value is visible in the file, so
both cases are flagged the same as a line with a literal default would be.
COPY lines
A typical Dockerfile has several ordinary COPY instructions in a row --
package.json, source directories, config files -- and a
COPY .env /app/.env or COPY id_rsa /root/.ssh/id_rsa reads no differently
from any of them on a skim unless a reviewer is deliberately checking each source's basename against
a list of well-known credential filenames. This tool checks every COPY/ADD
source against that fixed list every time, so the answer does not depend on a reviewer's memory of
which filenames count.
This is a name-pattern heuristic, not a value scanner -- it never sees what a build actually resolves
ARG or ENV to, so a name like API_KEY is flagged whether or not
the value behind it is sensitive, and a genuine secret under a name this tool's pattern list does not
recognise is a false negative it cannot close. Deciding whether a specific flagged instruction is a
real exposure, and catching a secret under an unrecognised name, is still a job for reading the
Dockerfile yourself.
A reviewer who knows to look can spot the obvious case immediately: an ARG or ENV line with a literal-looking secret value sitting right there in the text, such as ARG DB_PASSWORD=hunter2. That review genuinely works when the value is literal and the line is short -- the same case this tool's classify.mjs also flags as arg-literal or env-secret.
ENV NODE_ENV=production API_KEY=$API_KEY carries no literal secret text on that line for a reviewer to react to -- the value only exists once the build resolves the ARG reference. But per Docker's own documentation, whatever that value resolves to is written into the image's config layer exactly the same as a literal would be, and stays there. A reviewer scanning for a suspicious-looking string has nothing to see on this line; this tool flags it because it checks the ENV variable's name against a secret-pattern list, not the literal text of its value.
ARG SIGNING_TOKEN with no default commits nothing to the Dockerfile itself, so on a skim it looks like the safe version of the ARG PASSWORD=hunter2 pattern a reviewer already knows to flag. It is still worth a second look: it invites a caller to pass a value with --build-arg, which BuildKit still records for the build unless that value is mounted as a build secret instead. This tool flags it too, as an advisory-only arg-declared finding, so it does not get silently classed as fine because it has no visible value.
A Dockerfile can carry a dozen ordinary COPY instructions -- package.json, source directories, config files -- and a COPY .env /app/.env or COPY id_rsa /root/.ssh/id_rsa reads the same at a glance as any of them unless a reviewer is specifically checking each source path against a list of well-known credential filenames (.env, id_rsa, .npmrc, .aws/credentials, and others). That list is easy to not have fully in mind while reading past several ordinary-looking COPY lines in a row. This tool checks every COPY and ADD source's basename and path against that fixed list every time, regardless of how many other COPY lines surround it.
No. This is a name-pattern heuristic over Dockerfile text, not a value scanner -- it never sees what a build actually resolves ARG or ENV to, so a name like API_KEY is flagged because it looks like a secret even if the value behind it is not sensitive. Deciding whether a specific flagged instruction is a real exposure, and catching a secret under a name this tool's pattern list does not recognise, is still a job for reading the Dockerfile yourself.