Docker Engine v28 Hardening Container Networking by Default
December 8, 2025 · 913 words · 5 min
Docker simplifies containerization by removing runtime complexity and making app development seamles
Docker simplifies containerization by removing runtime complexity and making app development seamless. With , we’re taking another step forward in security by ensuring containers aren’t unintentionally accessible from local networks. This update isn’t about fixing a single vulnerability — it’s about security hardening so your containers stay safe. When you run a container on the default Docker “bridge” network, Docker sets up rules using your system’s firewall (via ). For example, the following command forwards traffic from port 8080 on your host to port 80 in the container. However, if your host’s chain is permissive (i.e., by default)
is enabled, unpublished ports could also be remotely accessible under certain conditions. This only affects hosts on the as the Docker host. In multi-tenant LAN environments or other shared local networks, someone connected on an RFC1918 subnet (such as or ) could reach unpublished container ports if they knew (or guessed) its IP address. This behavior only affects Linux users running Docker versions earlier than 28.0.0 with . Docker Desktop is affected. If you installed Docker on a single machine and used our defaults, without manually customizing your firewall settings, you’re likely unaffected by upgrading. However, you could be impacted if: If any of these exceptions apply to you, you might notice that containers previously reachable by direct IP now appear blocked unless you opt out or reconfigure your networking. This exposure would’ve required being or otherwise having route-level access to the container’s RFC1918 IP range. It affect machines across the public internet. However, a malicious user could discover unpublished container ports, within LAN settings or corporate environments, and connect to them. For instance, they might add a custom route to the container’s subnet, using the following command: From there, if is your Docker host with a permissive firewall, the attacker could send packets straight to (the container’s IP). If you’ve been impacted, we recommend taking the following three steps: Docker Engine 28.0 now drops traffic to unpublished ports by default. This “secure by default” approach prevents containers from being unexpectedly accessible on the LAN. Most users won’t notice a difference, published ports will continue to function as usual ( ), and unpublished ports remain private as intended. If you connect to containers over the LAN without publishing ports, you have a couple of options: In , add the following: Or you can run Docker with the flag. This preserves a globally open chain. But keep in mind that Docker still drops traffic for unpublished ports using separate rules. See Option 2 for a fully unprotected alternative. Advanced users with complex network setups can manually configure iptables to allow exactly the traffic they need. But this route is only recommended if you’re comfortable managing firewall rules. In previous Docker Engine versions, Docker’s reliance on a permissive chain meant that containers on the default bridge network could be reached if: In Docker 28.0, we now explicitly drop unsolicited inbound traffic to each container’s internal IP unless that port was explicitly published ( or ). This doesn’t affect local connections from the Docker host itself, but it does block remote LAN connections to unpublished ports. Suppose you have two hosts on the same RFC1918 subnet: DockerHost runs a container with IP , and Docker’s firewall policy is effectively “ACCEPT.” In this situation, an attacker could run the following command: If MySQL was listening on port 3306 in the container (unpublished), Docker might still forward that traffic. The container sees a connection from , and no authentication is enforced by Docker’s network stack alone. By enforcing a drop rule for unpublished ports, Docker 28.0 now prevents the above scenario by default. Ensures that local traffic to container IPs is discarded unless explicitly published. Originally, if Docker had to enable IP forwarding, it would set by default. Now, Docker only applies that if necessary and extends the same logic to IPv6. You can opt-out with or in the config file. The container remains accessible from the host itself, but not from other devices on the LAN (unless you intentionally choose “nat-unprotected”). Some users have raised concerns about local-network exposure for years (see issues like and ). But there’s been a lot of change since then: By introducing these changes in Docker Engine 28.0, we align with today’s best practices: . It’s a shift away from relying on users to configure their own firewalls if they want to lock things down. These changes are backward compatible for users who rely on direct container IP access from a local LAN. For the majority, the new defaults lock down containers more securely without breaking typical scenarios. Still, we strongly advise upgrading to 28.0.1 or later so you can benefit from: Before you upgrade, here’s a recommended checklist to run through to make sure you’re set up for success with the latest release: By hardening default networking rules in Docker Engine 28.0, we’re reducing accidental container exposure on local networks. Most users can continue without disruption and can just enjoy the extra peace of mind. But if you rely on older behaviors, you can opt out or create specialized networks that bypass these rules. Follow our to get Docker Engine 28.0 on your system today. We appreciate the feedback from the community and encourage you to reach out if you have questions or run into surprises after upgrading. You can find us on , our , or your usual support channels.