Why Docker’s 127.0.0.1 Port Mapping Still Exposes Services – Proof and Fix
A recent Hacker News discussion revealed that Docker’s iptables rule allows containers bound to 127.0.0.1 to be reachable from other hosts, and a step‑by‑step proof‑of‑concept demonstrates the issue while a revised iptables rule is proposed to enforce proper source‑address restrictions.
Background
Docker’s -p flag can bind a container port to a specific host address, for example -p 127.0.0.1:80:80. The intention is that only processes on the host loopback interface can reach the service. In practice Docker adds an iptables rule that accepts traffic from any source to the container’s IP address, which bypasses the loopback restriction.
iptables -nvL DOCKER
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:80Because the rule matches packets destined for 172.17.0.2:80, an attacker on the same network can connect directly to the container, rendering the 127.0.0.1 binding ineffective.
Proof of Concept
The issue can be reproduced with a PostgreSQL container.
Start a container on host A (IP 192.168.0.100) and bind the PostgreSQL port to the loopback address:
docker run -e POSTGRES_PASSWORD=password -p 127.0.0.1:5432:5432 postgresOn host B (IP 192.168.0.200) add a static route so that traffic for the Docker bridge network ( 172.16.0.0/12) is sent via host A: ip route add 172.16.0.0/12 via 192.168.0.100 Scan host A from B to verify that the PostgreSQL port is reachable:
nmap -p5432 -Pn --open 172.16.0.0/12
PORT STATE SERVICE
5432/tcp open postgresqlConnect directly to the container using its bridge IP: psql -h 172.17.0.2 -U postgres The service is reachable despite being bound to 127.0.0.1 on the host.
Proposed Fix
The iptables rule generated for -p 127.0.0.1:5432:5432 currently looks like:
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:5432To enforce the intended source restriction, the rule should specify both the inbound interface and the allowed source network. For a loopback binding the corrected rule is:
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- lo docker0 127.0.0.0/8 172.17.0.2 tcp dpt:5432If the host address is 192.168.0.100/24 and the port is published with -p 192.168.0.100:5432:5432, the rule should be:
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- eth0 docker0 192.168.0.0/24 172.17.0.2 tcp dpt:5432In addition, Docker should default to binding to 127.0.0.1 when the -p flag is used without an explicit IP address. The practical mitigation is for Docker to release a patched version that generates the stricter iptables rules, and for operators to upgrade promptly.
Reference: Hacker News discussion https://news.ycombinator.com/item?id=31839936
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
