Binding to an Unrestricted IP Address
Description
Binding to an Unrestricted IP Address occurs when the product assigns the address 0.0.0.0 to a database server, cloud service, or remote computing resource. When a server binds to 0.0.0.0, it allows connections from every IP address on the local machine, effectively exposing the server to every possible network. This creates broader access than developers or administrators typically intend, potentially exposing services to untrusted networks.
Risk
Binding to unrestricted addresses has severe implications. Service exposed to all networks. Denial of service amplification possible. Unauthorized access from unexpected networks. Internal services exposed externally. Security boundaries violated. Data exfiltration enabled. Attack surface significantly increased. Network segmentation bypassed. High likelihood of exploitation when combined with other vulnerabilities.
Solution
Assign IP addresses other than 0.0.0.0 during system configuration phase (high effectiveness). Use firewalls or packet filtering to deny unwanted connections (high effectiveness). Bind to specific interface addresses (127.0.0.1 for local-only, specific IP for controlled access). Document and review all network bindings during security audits.
Common Consequences
| Impact | Details |
|---|---|
| Availability | Scope: Availability Denial of service through amplified traffic when service is exposed to all networks. |
| Confidentiality | Scope: Confidentiality Unauthorized access to services from unexpected networks. |
Example Code
Vulnerable Code
# Vulnerable: Python server binding to 0.0.0.0
import socket
from http.server import HTTPServer, SimpleHTTPRequestHandler
# VULNERABLE: Binds to all interfaces
def vulnerable_start_server():
host = '0.0.0.0' # VULNERABLE: All interfaces
port = 8080
# Creates server accessible from any network
server = HTTPServer((host, port), SimpleHTTPRequestHandler)
print(f"Server running on {host}:{port}")
server.serve_forever()
# VULNERABLE: Database connection exposed
def vulnerable_database_server():
import sqlite3
import socketserver
class DatabaseHandler(socketserver.BaseRequestHandler):
def handle(self):
# Process database queries...
pass
# VULNERABLE: Database accessible from all networks
server = socketserver.TCPServer(('0.0.0.0', 5432), DatabaseHandler)
server.serve_forever()
// Vulnerable: Node.js Express server
const express = require('express');
const app = express();
// VULNERABLE: Listening on all interfaces
app.listen(3000, '0.0.0.0', () => {
console.log('Server running on 0.0.0.0:3000');
});
// VULNERABLE: WebSocket server on all interfaces
const WebSocket = require('ws');
const wss = new WebSocket.Server({
host: '0.0.0.0', // VULNERABLE
port: 8080
});
// Internal admin API exposed to all networks
const adminApp = express();
adminApp.get('/admin/users', (req, res) => {
// Returns sensitive user data
res.json(getAllUsers());
});
// VULNERABLE: Admin interface on all interfaces
adminApp.listen(9000, '0.0.0.0');
# Vulnerable: Puppet configuration
# VULNERABLE: Signing server exposed to all networks
class { 'puppetserver':
listenaddr => '0.0.0.0', # VULNERABLE: All interfaces
}
# This exposes the Puppet signing server to potential
# denial-of-service attacks from the entire network
# Vulnerable: Docker Compose configuration
version: '3'
services:
database:
image: postgres
ports:
- "0.0.0.0:5432:5432" # VULNERABLE: Exposes database to all networks
redis:
image: redis
ports:
- "0.0.0.0:6379:6379" # VULNERABLE: Redis exposed externally
admin:
image: admin-panel
ports:
- "0.0.0.0:8080:8080" # VULNERABLE: Admin panel exposed
// Vulnerable: Go HTTP server
package main
import (
"net/http"
)
func main() {
http.HandleFunc("/", handler)
// VULNERABLE: Binds to all interfaces
http.ListenAndServe("0.0.0.0:8080", nil)
}
// VULNERABLE: gRPC server
import "google.golang.org/grpc"
func startGRPCServer() {
// VULNERABLE: All interfaces
lis, _ := net.Listen("tcp", "0.0.0.0:50051")
grpcServer := grpc.NewServer()
grpcServer.Serve(lis)
}
Fixed Code
# Fixed: Python server with restricted binding
import socket
from http.server import HTTPServer, SimpleHTTPRequestHandler
import os
def secure_start_server():
# FIXED: Bind to localhost only (for local services)
host = '127.0.0.1'
port = 8080
server = HTTPServer((host, port), SimpleHTTPRequestHandler)
print(f"Server running on {host}:{port}")
server.serve_forever()
def secure_start_server_specific_interface():
# FIXED: Bind to specific interface from configuration
host = os.environ.get('BIND_ADDRESS', '127.0.0.1')
port = int(os.environ.get('PORT', 8080))
# Validate the bind address
allowed_addresses = ['127.0.0.1', '10.0.0.5', '192.168.1.100']
if host not in allowed_addresses:
raise ValueError(f"Invalid bind address: {host}")
server = HTTPServer((host, port), SimpleHTTPRequestHandler)
server.serve_forever()
# FIXED: Database server on internal network only
def secure_database_server():
import socketserver
class DatabaseHandler(socketserver.BaseRequestHandler):
def handle(self):
pass
# FIXED: Bind to internal network interface only
internal_ip = '10.0.0.5' # Internal network IP
server = socketserver.TCPServer((internal_ip, 5432), DatabaseHandler)
server.serve_forever()
// Fixed: Node.js Express server with restricted binding
const express = require('express');
const app = express();
// FIXED: Bind to localhost only
app.listen(3000, '127.0.0.1', () => {
console.log('Server running on 127.0.0.1:3000');
});
// FIXED: WebSocket server on localhost
const WebSocket = require('ws');
const wss = new WebSocket.Server({
host: '127.0.0.1', // FIXED: Localhost only
port: 8080
});
// FIXED: Admin API on localhost only
const adminApp = express();
adminApp.get('/admin/users', (req, res) => {
res.json(getAllUsers());
});
// FIXED: Admin interface only accessible locally
adminApp.listen(9000, '127.0.0.1');
// FIXED: Configuration-based binding with validation
const config = require('./config');
function startServer() {
const allowedHosts = ['127.0.0.1', '10.0.0.0/8', '192.168.0.0/16'];
const host = config.bindAddress || '127.0.0.1';
// FIXED: Validate bind address
if (!isAllowedHost(host, allowedHosts)) {
throw new Error(`Invalid bind address: ${host}`);
}
app.listen(config.port, host);
}
function isAllowedHost(host, allowedRanges) {
// Check if host is in allowed ranges
if (host === '127.0.0.1' || host === 'localhost') {
return true;
}
// FIXED: Explicitly reject 0.0.0.0
if (host === '0.0.0.0') {
return false;
}
// Check against allowed ranges...
return allowedRanges.some(range => isInRange(host, range));
}
# Fixed: Puppet configuration
# FIXED: Signing server bound to localhost
class { 'puppetserver':
listenaddr => '127.0.0.1', # FIXED: Localhost only
}
# Or for internal network only:
class { 'puppetserver':
listenaddr => '10.0.0.5', # FIXED: Specific internal IP
}
# Fixed: Docker Compose configuration
version: '3'
services:
database:
image: postgres
ports:
- "127.0.0.1:5432:5432" # FIXED: Localhost only
redis:
image: redis
# FIXED: No external port mapping
# Only accessible from within Docker network
expose:
- "6379"
admin:
image: admin-panel
ports:
- "127.0.0.1:8080:8080" # FIXED: Admin on localhost only
# FIXED: Public-facing service on specific interface
web:
image: web-server
ports:
- "192.168.1.100:80:80" # FIXED: Specific external IP
// Fixed: Go HTTP server with restricted binding
package main
import (
"net/http"
"os"
"net"
"strings"
)
func main() {
http.HandleFunc("/", handler)
// FIXED: Bind to localhost by default
bindAddr := getBindAddress()
http.ListenAndServe(bindAddr, nil)
}
func getBindAddress() string {
addr := os.Getenv("BIND_ADDRESS")
if addr == "" {
addr = "127.0.0.1" // FIXED: Safe default
}
// FIXED: Validate address
if addr == "0.0.0.0" {
panic("Binding to 0.0.0.0 is not allowed")
}
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
return net.JoinHostPort(addr, port)
}
// FIXED: Secure gRPC server
import "google.golang.org/grpc"
func startSecureGRPCServer() {
// FIXED: Bind to internal network only
bindAddr := os.Getenv("GRPC_BIND_ADDR")
if bindAddr == "" || bindAddr == "0.0.0.0" {
bindAddr = "127.0.0.1"
}
lis, err := net.Listen("tcp", bindAddr+":50051")
if err != nil {
panic(err)
}
grpcServer := grpc.NewServer()
grpcServer.Serve(lis)
}
CVE Examples
- CVE-2022-21947: Rancher Desktop Kubernetes bound services to 0.0.0.0, allowing network users unauthorized access to dashboard API.
- CVE-2020-10749: Kubernetes network policy bypass through services bound to all interfaces.
Related CWEs
- CWE-668: Exposure of Resource to Wrong Sphere (parent)
- CWE-417: Communication Channel Errors (category)
- CAPEC-1: Accessing Functionality Not Properly Constrained by ACLs
References
- MITRE Corporation. "CWE-1327: Binding to an Unrestricted IP Address." https://cwe.mitre.org/data/definitions/1327.html
- OWASP. "Network Security Cheat Sheet"
- Docker. "Networking Best Practices"