Description
Binding a server to 0.0.0.0 or an empty host address allows it to receive requests on multiple network interfaces. Actual external reachability also depends on routing and firewalls. Listening on all interfaces does not itself bypass authentication, but an internal service may expose sensitive information or administrative functions if its authentication, TLS and network controls do not match that exposure.
Potential impact
- An externally reachable administration, debugging or metrics endpoint without adequate protection may expose settings, tokens or session information.
- External clients may send requests directly to functions intended only for an internal network. Their actual permissions still depend on authentication and authorization.
- Unnecessarily exposed services may provide an entry point for attacks on vulnerable versions or accounts.
Remediation
- Specify the listening address. Use loopback or a required private interface address with
net.Listenortls.Listenfor internal services. - Manage addresses and ports per environment, and review whether listening on every interface is intentional in production.
- Restrict ports that do not need external access to approved networks or IP addresses using firewalls or cloud security groups.
- Behind a reverse proxy, restrict backend access to loopback in the same host and network namespace, or to the required private path for separate hosts or containers. Apply authentication and transport protection too.
- Periodically check actual listening sockets and externally reachable ports.
Examples
Before
go
package main
import (
"log"
"net"
)
// Example internal administration TCP server
func startAdminServer() {
// Bind to all interfaces (0.0.0.0); the internal port may be externally reachable
listener, err := net.Listen("tcp", "0.0.0.0:9000")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Println("accept error:", err)
continue
}
go func(c net.Conn) {
defer c.Close()
c.Write([]byte("admin status: OK\n"))
}(conn)
}
}
func main() {
startAdminServer()
}
After
go
package main
import (
"log"
"net"
"os"
)
// Internal administration TCP server with a local or private bind address
func startAdminServer() {
// Configure the address through the environment; default to localhost
addr := os.Getenv("ADMIN_BIND_ADDR")
if addr == "" {
// Bind only to 127.0.0.1 for local connections
addr = "127.0.0.1:9000"
}
listener, err := net.Listen("tcp", addr)
if err != nil {
log.Fatal(err)
}
defer listener.Close()
log.Printf("admin server listening on %s", addr)
for {
conn, err := listener.Accept()
if err != nil {
log.Println("accept error:", err)
continue
}
go func(c net.Conn) {
defer c.Close()
c.Write([]byte("admin status: OK\n"))
}(conn)
}
}
func main() {
startAdminServer()
}
Explanation:
- Before: The server listens on
0.0.0.0:9000. If the external connection path is allowed, clients can read its unauthenticated status response. - After: The default address is
127.0.0.1:9000. A configuredADMIN_BIND_ADDRis used as supplied, so trusted administrators must control deployment settings and verify the actual access scope.