#4760·gin

Engine.Run starts an HTTP server without default timeouts

Author: GG-FengCreated Jul 25, 2026Updated Aug 6, 2026
Labelstype/bug

Description

Summary

Engine.Run starts an http.Server without read, write, idle, or header timeouts.

This leaves applications that use the default Run helper exposed to slow-client resource exhaustion unless they manually create and configure their own http.Server.

Affected Code

File: gin.go

server := &http.Server{ // #nosec G112
    Addr:    address,
    Handler: engine.Handler(),
}
err = server.ListenAndServe()

ReadTimeout, WriteTimeout, ReadHeaderTimeout, and IdleTimeout are all left at their zero values.

Reproduction

I reproduced this with a minimal Gin server started through the default run path.

A TCP client sent only a partial HTTP request header, waited 20 seconds, and then completed the request:

GET /ping HTTP/1.1
Host: localhost

After the 20 second pause, the connection was still alive and the server returned a normal response once the request was completed:

HTTP/1.1 200 OK
Content-Type:

This shows that no ReadHeaderTimeout was applied by default.

Expected Behavior

The default server startup helper should either apply safe timeout defaults or strongly guide users toward a timeout-configured server for production use.

Actual Behavior

Engine.Run starts an HTTP server with no default timeouts.

Impact

Slow clients can keep connections open by delaying request headers. With enough concurrent slow connections, this can consume server connection resources and degrade availability.

Suggested Fix

  • Consider setting a conservative default ReadHeaderTimeout in the Run helper.
  • Alternatively, add a production-safe helper or prominent documentation warning that Engine.Run does not configure timeouts.
  • Recommend using an explicitly configured http.Server for production deployments.

Gin Version

Local gin-gonic/gin checkout at commit 34dac20

Can you reproduce the bug?

Yes

Source Code

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "pong")
	})

	if err := r.Run(":8080"); err != nil {
		panic(err)
	}
}

Run the server:

go run .

In another shell, open a TCP connection and send only a partial HTTP request header:

exec 3<>/dev/tcp/localhost/8080
printf 'GET /ping HTTP/1.1\r\nHost: localhost\r\n' >&3
sleep 20
printf '\r\n' >&3
timeout 3 dd bs=1 count=80 <&3 2>/dev/null

Observed behavior:

HTTP/1.1 200 OK
Content-Type:

The connection remains open after 20 seconds and the server responds normally once the request header is completed, showing that ReadHeaderTimeout is not applied by default.

Go Version

Go 1.26.5 in Docker golang:1.26

Operating System

Linux, inside Docker golang:1.26 container