July 24, 2023·3 min read·engineeringdockergohttp

Docker fixes HTTP host validation for local Go clients

Engine 24.0.5 repairs Go client compatibility after stricter HTTP validation. A Unix socket path was being used where the HTTP request needed a valid host value.

A local Unix socket does not need a DNS hostname, but an HTTP client still has rules about its Host field. Docker's Go client encountered that distinction when a Go security update tightened request validation. Engine 24.0.5, released July 24, includes the fix that stops local socket paths from being used as HTTP host values. The failure happened where Docker's local transport met a library designed around HTTP conventions.

This is a useful maintenance release to examine because the application protocol did not need a new feature. Existing requests needed to be represented correctly. A value that made sense as a connection destination had reached a field with different syntax and semantics. Stricter validation exposed that mismatch.

I value Docker's repeatable environments, but the client building or controlling them is itself software with dependencies. This fix is a concrete reminder that a stable daemon API does not describe every compatibility requirement of a program that calls it. The HTTP implementation in the client is another part of the execution path.

The socket path reached the wrong field

The backport discussion for Moby pull request 45962 explains the failure. Local Unix-socket and Windows named-pipe connections do not use a hostname to choose the daemon. Earlier client code could use its address as the HTTP hostname, including a Unix path such as /var/run/docker.sock.

The maintainers describe how Go 1.20.6 and 1.19.11 reject that value after the fix for CVE-2023-29406. Earlier behavior cleaned the header and stripped slashes. Depending on that cleanup allowed the representation error to persist until the library became stricter. The backport includes failing attach tests and their successful result after the correction. Those tests exercise attachment both with and without a terminal, which connects the representation fix to concrete client operations.

This distinguishes the failure from a missing socket or insufficient filesystem permissions. An invalid Host error concerns request construction. Changing the daemon's socket permissions does not make a pathname valid as an HTTP hostname. The diagnostic belongs to a different layer even when both problems prevent a client from completing the same operation.

A valid placeholder keeps the transport separate

The client implementation at version 24.0.5 defines DummyHost as api.moby.localhost. Its comment explains that the value supplies a valid hostname for local communication and should never be resolved. The actual connection continues to use the configured local transport.

The request construction code assigns this value to req.Host when the protocol is unix or npipe. That condition is important. The fix addresses transports whose connection address does not supply a meaningful HTTP authority. It does not replace the host of every remote Docker request with a local placeholder.

The resulting field can be represented as a short HTTP header fragment. It describes the protocol value, not a new network endpoint that an administrator needs to configure.

Host: api.moby.localhost

The source comment also explains a constraint in Go's HTTP implementation. Docker cannot simply treat an empty authority as though it were an ordinary supported HTTP-over-TCP configuration. The placeholder accommodates the library's requirements while keeping socket selection in the transport. A connection address and a protocol authority have different jobs even when a URL-shaped configuration combines them.

For authors of programs using the Go client, the relevant repair must be present in the client code compiled into the program. Upgrading a separately running daemon does not rewrite that program's request-construction implementation. This follows from the location of the fix and matters when several tools control the same daemon through independently built clients.

Image storage receives separate repairs

The release notes also list fixes for the containerd image backend. Image inspection now includes the platform variant, and export protects content from possible garbage collection during the operation. Other repairs address duplicate repository digests and operations against an incorrect tag when an image reference includes both a tag and digest.

These changes have a different cause from the HTTP compatibility issue. They concern whether image operations retain and identify the content they need. Exporting content is a period of active use, so garbage collection must not treat that content as disposable before export finishes. The export backport records that specific correction.

I regard this kind of patch as relevant to the usefulness of verifiable artifacts. A digest identifies content, but tools also have to preserve that content through the operation being requested. July's release repairs both a client representation error and several image-management behaviors, with the Host correction located in the Go client and the export correction in the containerd-backed image implementation.