skip to content

A registry password is passed as a container image build argument — why is it still recoverable from the published image?

level: juniorimportance: must knowfreq 66%

answer

  1. the artifact remembers its inputs
  2. layers ship whole and immutable
  3. deleting later only hides it
  4. build history records the argument
  5. pull access is all it takes

basics

~20 s

Build arguments are recorded in the image's build metadata, and any file written from one stays in that layer. Layers are immutable and ship whole, so deleting the file later hides it from a running container without removing it.

solid answer

~50 s

An image is an ordered stack of immutable layers plus a configuration document, and both of them keep the value. The image config commonly records the build history, including argument values substituted into the instruction that produced each layer, and if a step wrote the password into a package-manager config or a credentials file, those bytes are archived in that layer forever. Removing the file later only records a deletion marker in a higher layer — the running container no longer sees it, but anyone reading the image layer by layer does. The blast radius is therefore everyone who can *pull*, which for an internal image later mirrored to a public registry is an anonymous stranger. Treat the credential as compromised and rotate it; expose build-time secrets through a mount scoped to one step that is never committed to a layer.

go deeper

for a junior

Be ready to say plainly that an image is built from stacked, immutable layers and that a build-time value can end up in one of them. Knowing that a later delete does not undo an earlier write is the whole answer at this level.

for a middle

An interviewer expects the two independent routes: the recorded build history that carries substituted argument values, and any file the build wrote from the value. Explain why a deletion marker hides rather than removes.

for a senior

Show the response order — rotate first, rebuild second — and name the false green where a scan of the running container passes while the artifact still carries the credential. Reason about who can pull, not who can push.

for a principal

Own the systemic fix: make it structurally impossible for credentials to reach image builds, by moving authenticated fetches out of the image build and issuing short-lived scoped tokens, then verify it with artifact-content checks rather than trusting each team's discipline.

## The instinct that causes this A container image build takes parameters supplied at build time, and teams reach for them to hand the build a credential — a private artifact-registry password, an internal package-feed token — because the build genuinely needs to fetch something protected. The instinct is that a build-time input is transient: the build ends, the parameter goes away. It does not. The build's *output* is an artifact, and the artifact remembers. ## What an image actually is A published image is two things: an ordered set of filesystem layers, each a content-addressed archive of the changes one build step made, and a configuration document describing how the image was assembled and how it should run. Both of them can preserve a build-time credential, by two independent routes: 1. **The recorded build history.** Image configuration commonly carries a history of the instructions that produced each layer, with build-argument values already substituted in. Reading it needs no execution and no privilege beyond the ability to pull the image. 2. **Anything the build wrote from the value.** If a step materialises the token into a package-manager configuration file, a credentials file, or a rendered properties file, those bytes become part of that layer's archive. ## Why deleting it later does nothing Layers are additive and immutable. A later step that removes the file does not reach back and rewrite the earlier archive; it records a *deletion marker* in a higher layer, which hides the path from the flattened filesystem a running container sees. The original bytes are untouched and are distributed with the image. This is the trap behind a very common false green: a filesystem scan of a *running* container comes back clean, while the credential is still sitting in the artifact one layer down. Anyone who unpacks the image offline, layer by layer, reads the file exactly as it was written. ## Who can read it The blast radius is the set of people who can pull, not the set of people who can push. That set is usually much larger than the team expects, and it grows silently: an internal service image gets mirrored to a public registry so a partner or an edge fleet can pull it, and now an anonymous internet user with no account and no exploit downloads the image and reads out the credential. The read leaves no trace you control, so you cannot later prove it did not happen. ## Get the direction of the failure right This is not a logging failure. Log masking — the CI feature that redacts registered secret values from a job's log stream — is irrelevant here, because the secret never had to appear in a log at all; it left inside the artifact. Nor is it something an inventory document catches: a software bill of materials enumerates the components an artifact is built from, not the arbitrary file contents it carries, and build provenance describes how the artifact came to be, not what is embedded in it. A credential in a layer is an *artifact content* problem, and only controls that look at artifact contents, or that keep the value out in the first place, address it. ## What to do instead - **Keep the credential out of the build entirely.** Fetch the protected dependencies in a separate step or job that holds the credential, and pass the resulting files into the image build as ordinary inputs. - **Use a build-time secret mechanism.** Modern build engines can expose a value to one step through a mount that is never committed to a layer and never recorded in the build history. That is the difference between a secret the build *uses* and a secret the build *contains*. - **Never move it to a runtime environment variable in the image configuration** as the fix. That is the same distribution problem with a wider audience: every runtime that starts the image reads the config. - **Shorten and narrow the credential.** A short-lived, single-purpose token turns a permanent published secret into an expiring one, which is not a substitute for the fix but is a real reduction in blast radius. ## If it already shipped Rotate first, then rebuild. Deleting the tag does not un-distribute the bytes — anyone who already pulled keeps them, and mirrors and local caches keep them too. After rotation, work out what that credential could reach and check for use of it; the exposure window starts at the push, not at the discovery.

  • A filesystem scan of the running container finds nothing. Does that clear the image?
    No. A running container sees the flattened filesystem, where a deletion marker in a higher layer hides the file. The bytes are still in the lower layer and in the distributed image, and the recorded build history is not part of the filesystem at all. Clearing the image means inspecting layers and configuration, not the runtime view.
  • The image was already mirrored to a public registry. What is your response order?
    Rotate or revoke the credential first, because that is the only step that shrinks the exposure — everything else is cleanup. Then rebuild without the build argument and republish, work out what the credential could reach and look for use of it, and note that removing tags does not recall copies that have already been pulled or mirrored.
  • Why doesn't the CI's log masking protect you here?
    Masking redacts registered secret values from a job's log stream. The credential in this failure never entered the log stream — it left the pipeline inside the published artifact, through a channel masking does not touch. Masking is a net over one output, not a boundary around the secret.

Erasing the whiteboard does not erase the photograph somebody already took of it. The image is the photograph.

saying these in an interview costs you the question

  • Claims deleting the file in a later step removes it from the image
  • Thinks build arguments are discarded when the build finishes
  • Assumes only accounts with push access can read image layers
  • Says the secret is safe because it never reached the build log
  • Suggests base64-encoding the value before passing it in

context