Skip to main content

SEC013-bind-all-interfaces — Server binds to all network interfaces

PropertyValue
DimensionSecurity
Default severityMedium
ConfidenceMedium
CWECWE-1327
LanguagesRust, Python, JavaScript, TypeScript

What it detects​

Flags call sites where a server or socket is bound to "0.0.0.0" (all IPv4 interfaces) or "::" (all IPv6 interfaces). Both of these "any-address" values expose the listening service on every network interface — including public-facing ones — which is rarely the correct behaviour in production.

The rule also recognises the host:port forms: "0.0.0.0:8080" and "[::]:8080" are treated the same as the bare any-address strings.

Detection is syntactic only: the rule checks whether a string literal passed to a known bind callee equals or starts with an any-address value. It does not perform data-flow analysis, so if the address is built dynamically the rule will not fire.

Why it matters​

A service bound to 0.0.0.0 or :: accepts inbound connections on every network interface on the host, including the public internet-facing interface. If the service is intended to be reachable only from localhost (e.g. a health-check endpoint, an admin API, or a development server) this can expose it to unauthorised access.

Restricting the bind address to 127.0.0.1 or ::1 at the code level is a simple defence-in-depth measure that does not rely on firewall rules being correctly applied.

Examples — flagged​

Python (Flask):

app.run("0.0.0.0", port=5000) # FLAGGED — any IPv4 interface
uvicorn.run(app, host="0.0.0.0") # FLAGGED — any IPv4 interface (kwarg)
socket.bind(("0.0.0.0", 8080)) # FLAGGED — any IPv4 interface (tuple)

Rust:

TcpListener::bind("0.0.0.0:8080") // FLAGGED — any IPv4 interface
TcpListener::bind("::") // FLAGGED — any IPv6 interface

JavaScript/TypeScript:

app.listen("0.0.0.0", 3000); // FLAGGED — any IPv4 interface
server.listen("::"); // FLAGGED — any IPv6 interface

Examples — not flagged​

Python:

app.run("127.0.0.1", port=5000) # OK — loopback only
uvicorn.run(app, host="::1", port=8000) # OK — IPv6 loopback

Rust:

TcpListener::bind("127.0.0.1:8080") // OK — loopback only
TcpListener::bind("[::1]:8080") // OK — IPv6 loopback

JavaScript/TypeScript:

app.listen("127.0.0.1", 3000); // OK — loopback only
app.listen(3000); // OK — port-only, no all-interface string

Configuration​

No configuration knobs in v1. The bind-callee allowlist is hard-coded to the most common server-construction function names in each language:

LanguageRecognized callees
Rustbind, bind_addr, new (last path segment)
Pythonbind, run, listen (bare name or attribute method)
JavaScript/TypeScriptlisten, bind (bare name or member-expression method)

Fix guidance​

  1. Use loopback: Replace "0.0.0.0" with "127.0.0.1" (or "::" with "::1") when the service is intended to be localhost-only.
  2. Use an environment variable: If the bind address needs to be configurable (e.g. 0.0.0.0 in a container), read it from an environment variable so the policy is enforced at deployment time, not in source code.
  3. Add a firewall rule as defence-in-depth: Even when 0.0.0.0 is intentional, ensure that the port is firewalled from public access at the infrastructure level.

References​

Implementation​