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

ImpactDetails
AvailabilityScope: Availability

Denial of service through amplified traffic when service is exposed to all networks.
ConfidentialityScope: 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.

  • 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

  1. MITRE Corporation. "CWE-1327: Binding to an Unrestricted IP Address." https://cwe.mitre.org/data/definitions/1327.html
  2. OWASP. "Network Security Cheat Sheet"
  3. Docker. "Networking Best Practices"