Skip to content

Set ReadHeaderTimeout on the HTTP server - #1626

Open
randomizedcoder wants to merge 1 commit into
prometheus:masterfrom
randomizedcoder:http-read-header-timeout
Open

Set ReadHeaderTimeout on the HTTP server#1626
randomizedcoder wants to merge 1 commit into
prometheus:masterfrom
randomizedcoder:http-read-header-timeout

Conversation

@randomizedcoder

Copy link
Copy Markdown
Contributor

The &http.Server{} handed to web.ListenAndServe left ReadHeaderTimeout unset, so request-header reads were unbounded — a Slowloris-style connection-exhaustion vector (gosec G112). The exporter-toolkit does not set any server timeouts either.

Set ReadHeaderTimeout to one minute. It bounds only header reading, not the probe handler, so it never affects legitimate probe requests (which can legitimately run for the full scrape timeout). Happy to adjust the value if a different bound is preferred.

go build, go vet, go test ./... pass; gosec G112 clears.

🤖 Generated with Claude Code

@randomizedcoder
randomizedcoder force-pushed the http-read-header-timeout branch from 2ac8d67 to 585a13c Compare July 20, 2026 14:33
The &http.Server{} handed to web.ListenAndServe left ReadHeaderTimeout
unset, so request-header reads were unbounded — a Slowloris-style
connection-exhaustion vector (gosec G112). The exporter-toolkit does not
set any server timeouts either.

Set ReadHeaderTimeout to one minute via a small newServer constructor. It
bounds only header reading, not the probe handler, so it never affects
legitimate probe requests (which can run for the full scrape timeout).

Add a regression test that drives a stalled-header client against the
server built by newServer and asserts the connection is closed once the
timeout elapses, while a well-formed request still succeeds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: randomizedcoder <dave.seddon.ca@gmail.com>
@randomizedcoder
randomizedcoder force-pushed the http-read-header-timeout branch from 585a13c to c52d0a8 Compare July 20, 2026 14:47
randomizedcoder added a commit to randomizedcoder/exporter-toolkit that referenced this pull request Jul 20, 2026
The *http.Server built by Runner.newServer left ReadHeaderTimeout unset,
so request-header reads were unbounded -- a Slowloris-style connection
exhaustion vector (gosec G112). The exporter-toolkit web package does not
set server timeouts either, so every bootstrap-based exporter inherited
the gap.

Set ReadHeaderTimeout to one minute. It bounds only header reading, not
the metrics handler, so it never affects legitimate scrapes. The value is
a package var so tests can shorten it.

Follow-up to prometheus/blackbox_exporter#1626, which made the same change
on the caller side; setting it here fixes it once for all toolkit users.

go build, go vet, and go test ./... pass; gosec G112 clears.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: randomizedcoder dave.seddon.ca@gmail.com <dave.seddon.ca@gmail.com>
randomizedcoder added a commit to randomizedcoder/exporter-toolkit that referenced this pull request Jul 23, 2026
The *http.Server built by Runner.newServer left ReadHeaderTimeout unset,
so request-header reads were unbounded -- a Slowloris-style connection
exhaustion vector (gosec G112). The exporter-toolkit web package does not
set server timeouts either, so every bootstrap-based exporter inherited
the gap.

Add a ReadHeaderTimeout field to bootstrap.Config, defaulting to one
minute when unset. It bounds only header reading, not the metrics
handler, so it never affects legitimate scrapes, and -- like every other
Config field -- downstream exporters can tune it to their own needs.

Follow-up to prometheus/blackbox_exporter#1626, which made the same change
on the caller side; setting it here fixes it once for all toolkit users.

go build, go vet, and go test ./... (incl. -race) pass; gosec G112 clears.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: randomizedcoder dave.seddon.ca@gmail.com <dave.seddon.ca@gmail.com>
randomizedcoder added a commit to randomizedcoder/exporter-toolkit that referenced this pull request Jul 23, 2026
The *http.Server built by Runner.newServer left ReadHeaderTimeout unset,
so request-header reads were unbounded -- a Slowloris-style connection
exhaustion vector (gosec G112). The exporter-toolkit web package does not
set server timeouts either, so every bootstrap-based exporter inherited
the gap.

Add a ReadHeaderTimeout field to bootstrap.Config, defaulting to one
minute when unset. It bounds only header reading, not the metrics
handler, so it never affects legitimate scrapes, and -- like every other
Config field -- downstream exporters can tune it to their own needs.

Follow-up to prometheus/blackbox_exporter#1626, which made the same change
on the caller side; setting it here fixes it once for all toolkit users.

go build, go vet, and go test ./... (incl. -race) pass; gosec G112 clears.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: randomizedcoder dave.seddon.ca@gmail.com <dave.seddon.ca@gmail.com>
randomizedcoder added a commit to randomizedcoder/exporter-toolkit that referenced this pull request Jul 23, 2026
The *http.Server built by Runner.newServer left ReadHeaderTimeout unset,
so request-header reads were unbounded -- a Slowloris-style connection
exhaustion vector (gosec G112). The exporter-toolkit web package does not
set server timeouts either, so every bootstrap-based exporter inherited
the gap.

Add a ReadHeaderTimeout field to bootstrap.Config, defaulting to one
minute when unset. It bounds only header reading, not the metrics
handler, so it never affects legitimate scrapes, and -- like every other
Config field -- downstream exporters can tune it to their own needs.

Follow-up to prometheus/blackbox_exporter#1626, which made the same change
on the caller side; setting it here fixes it once for all toolkit users.

go build, go vet, and go test ./... (incl. -race) pass; gosec G112 clears.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: randomizedcoder dave.seddon.ca@gmail.com <dave.seddon.ca@gmail.com>
randomizedcoder added a commit to randomizedcoder/exporter-toolkit that referenced this pull request Jul 23, 2026
The *http.Server built by Runner.newServer left ReadHeaderTimeout unset,
so request-header reads were unbounded -- a Slowloris-style connection
exhaustion vector (gosec G112). The exporter-toolkit web package does not
set server timeouts either, so every bootstrap-based exporter inherited
the gap.

Add a ReadHeaderTimeout field to bootstrap.Config, defaulting to one
minute when unset. It bounds only header reading, not the metrics
handler, so it never affects legitimate scrapes, and -- like every other
Config field -- downstream exporters can tune it to their own needs.

Follow-up to prometheus/blackbox_exporter#1626, which made the same change
on the caller side; setting it here fixes it once for all toolkit users.

go build, go vet, and go test ./... (incl. -race) pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: randomizedcoder dave.seddon.ca@gmail.com <dave.seddon.ca@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant