Skip to main content

Resource Allocation Without Limits in net/http Package

📐 GO007
🏷️ resource_allocation_without_limits
ℹ️ CWE-770
⚠️ Warning

The Go standard library provides convenient functions such as net/http.ListenAndServe, net/http.ListenAndServeTLS, net/http.Serve, and net/http.ServeTLS to quickly start HTTP and HTTPS servers. However, a significant security issue with these functions is that they do not allow developers to specify critical timeout values—such as ReadTimeout, WriteTimeout, or IdleTimeout—on the server. By default, these timeouts are unset (zero), meaning the server will wait indefinitely for clients to send or receive data. This behavior can be exploited by malicious actors using techniques like Slowloris attacks, where an attacker intentionally opens many connections and sends data very slowly to exhaust server resources. Without timeouts, each connection can tie up a goroutine and file descriptor, leading to resource exhaustion and making the server susceptible to denial-of-service (DoS) attacks.

Beyond malicious intent, the absence of timeouts also increases the risk from buggy or misbehaving clients that inadvertently leave connections open, potentially causing the same resource exhaustion problem. In production environments, it is critical to protect against both unintentional and intentional abuse by configuring sensible timeouts on all HTTP servers. Since the shortcut functions (ListenAndServe, etc.) do not provide any parameters for timeout configuration, developers must instead use an http.Server struct and explicitly set the timeout fields. Failing to do so can compromise both the availability and stability of the server, making this an important security and operational concern.

Examples

package main

import (
"io"
"log"
"net/http"
)

func main() {
helloHandler := func(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "Hello, world!\n")
}

http.HandleFunc("/hello", helloHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}

Remediation

To mitigate resource exhaustion risks, replace with http.Server or similar with proper timeout values.

package main

import (
"io"
"log"
"net/http"
"time"
)

func main() {
helloHandler := func(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "Hello, world!\n")
}

mux := http.NewServeMux()
mux.HandleFunc("/hello", helloHandler)

server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
}

log.Fatal(server.ListenAndServe())
}

False Positives

In the case of a false positive the rule can be suppressed. Simply add a trailing or preceding comment line with either the rule ID (GO007) or rule category name (resource_allocation_without_limits).

Fix Iconfix
package main

import (
"io"
"log"
"net/http"
)

func main() {
helloHandler := func(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "Hello, world!\n")
}

http.HandleFunc("/hello", helloHandler)
// suppress: GO007
log.Fatal(http.ListenAndServe(":8080", nil))
}

See also