HabrAugust 12, 2026🇷🇺Translated from Russian

Where Secrets Really End Up in Docker Images: Testing 8 Common Methods

A comprehensive technical investigation examined exactly where secrets end up when building Docker images using eight different techniques. The tests used Ubuntu 24.04.1 LTS, Docker Engine 29.1.3, and BuildKit v0.26.2, with a test secret string SUPER_SECRET_KOTY_HULIGANY_2026 placed in various ways.

The first method, COPY, adds the secret file directly into an image layer. Even after running docker history, the file remains fully recoverable by extracting layers from a saved tar archive. Adding a subsequent RUN rm command only marks the file as deleted in a new layer; the original data stays intact in the previous layer.

Using ENV stores the secret value in the image configuration JSON under config.Env and also appears in build history. The ARG instruction keeps the value in history.created_by fields even though it does not appear in the final container environment.

The dedicated BuildKit Secrets feature, invoked with --mount=type=secret and --secret build flag, mounts the secret only temporarily during the RUN step. After the build completes, the value is absent from all layers, configuration JSON files, and history entries.

Multi-stage builds also proved effective when the secret is created and used only in an intermediate stage and never copied into the final image. No trace of the secret appears in the published artifact.

Combining echo and rm inside a single RUN instruction still leaves the secret string visible in build history and created_by metadata. Overwriting a copied file with a new value similarly fails because the original layer remains unchanged.

The experiments confirm that only two approaches — BuildKit Secrets and properly isolated multi-stage builds — avoid embedding secrets in the final Docker image. All other common patterns leave extractable data that can be recovered without ever starting a container.

Related articles

HabrSupply Chain & Open Source

redb 3.7.2 Released with Custom gRPC Protocol, Dependency Vulnerability Fixes and .NET 10 Migration

The redb ecosystem released versions 3.7.0, 3.7.1 and 3.7.2 in quick succession after 3.7.0 was withdrawn due to high-severity vulnerabilities in its .NET 9 build artifacts. NuGet audit detected issues only on full rebuilds, leading to updates for SSH.NET, Microsoft.Data.Sqlite, System.Security.Cryptography.Xml and Microsoft.Bcl.Memory across redb.Route, redb.Core, redb.Export and redb.Identity. The release introduces a native GrpcWire implementation that registers individual gRPC methods as routes on a shared Kestrel host, supports bidirectional streaming, real gRPC status codes and mTLS with pinned client certificates. redb.Route also gained a dedicated SOAP connector, Control Bus messaging for route lifecycle management and a corrected Claim Check pattern. File transports received critical fixes that prevent silent data loss when readLock and idempotency options are combined. All libraries now target net8.0;net9.0;net10.0 while host applications require .NET 10, aligning with Microsoft’s shortened support timeline for .NET 8 and 9.

安全客Supply Chain & Open Source

Poisoned Rust Crates Execute Malware at Build Time: 245 Million Downloads Hit in Supply-Chain Attack

Three widely used Rust crates on crates.io were poisoned on August 20 with malicious versions that execute automatically during cargo build. The attack leveraged a typosquatted proc-macro1 dependency containing a build script that downloads payloads and establishes persistence. arrayref alone has accumulated 245 million downloads and is pulled automatically through caret ranges in many dependency trees. Attack infrastructure overlaps with prior campaigns attributed to Sapphire Sleet and MIDNIGHT NEPTUNE. Rust security teams yanked the malicious releases within 86-107 minutes, but the incident highlights missing publish-age controls and weak maintainer-account protections in the Cargo ecosystem.

HabrSupply Chain & Open Source

PyPI Explores Prefix Reservation for Organizations Under PEP 752 to Prevent Name Squatting

PEP 752 proposes reserving package name prefixes for organizations on PyPI, allowing control over entire families of related package names rather than individual entries. The change addresses dependency confusion and name squatting risks where attackers register packages with familiar prefixes like google-cloud- or opentelemetry- to exploit user trust. Analysis of over 800,000 PyPI projects by CodeScoring shows that prefixes are rarely controlled by a single owner, with ecosystems like aws- managed by hundreds of accounts. The proposal introduces implicit namespaces and new metadata for clients and proxies while preserving the flat namespace model familiar to Python developers. PEP 755 will define the governance process for granting prefix rights, limiting applications to organizations and requiring clear justification. Existing packages receive backward compatibility exceptions, and the mechanism does not transfer across repositories.

HabrSupply Chain & Open Source

Suspicious Certificate Issuer Detected in MAX Messenger Windows Update Package

A detailed observation from a security researcher highlights an unexpected change in the code signing certificate for the MAX messenger desktop client on Windows. The August update package was signed by an individual named Konstantin Syomochkin instead of the usual Communication Platform LLC. This discrepancy raised concerns about potential supply chain interference linked to recent EU sanctions against the developer. The certificate was issued shortly after sanctions and belongs to a person based in Astana, Kazakhstan, with limited public ties to the VK team. Official MSI installers downloaded directly from the MAX website remain signed by the company, while the client-triggered update differs in both version and signer. The researcher recommends that VK verify the download chain through Mail.ru trackers to rule out tampering. Installation of the update was declined pending further clarification.