Skip to content

bootstrap: set ReadHeaderTimeout on the HTTP server - #421

Merged
ArthurSens merged 1 commit into
prometheus:masterfrom
randomizedcoder:bootstrap-read-header-timeout
Aug 25, 2026
Merged

bootstrap: set ReadHeaderTimeout on the HTTP server#421
ArthurSens merged 1 commit into
prometheus:masterfrom
randomizedcoder:bootstrap-read-header-timeout

Conversation

@randomizedcoder

@randomizedcoder randomizedcoder commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Hi again 👋 — a small hardening follow-up, as mentioned in #420.

Why

Runner.newServer in bootstrap/ returns &http.Server{Handler: mux} with ReadHeaderTimeout unset, so request-header reads are unbounded — a Slowloris-style connection-exhaustion vector (gosec G112). Because the web package does not set server timeouts either, every bootstrap-based exporter inherits the gap.

This is the toolkit-side counterpart to prometheus/blackbox_exporter#1626, which set the same timeout on the caller side. Fixing it here addresses it once for all toolkit users.

What

Add a ReadHeaderTimeout time.Duration 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 (which can run for the full scrape timeout), and — like every other Config field — downstream exporters can tune it to their own needs.

Table-driven tests assert the field maps onto the server (default when unset, configured value otherwise, non-positive treated as unset); a behavioral test confirms the server closes a connection whose headers never complete while a well-formed request still succeeds.

Thanks to @nicolastakashi for the excellent suggestion to make this a Config field rather than a package-level var — it's a much better fit for how the rest of Config is configured (plain struct fields, not functional options) and lets downstream exporters tune it too.

go build, go vet, go test ./... (incl. -race) pass; gosec G112 clears. Happy to adjust the value if a different bound is preferred.

🤖 Generated with Claude Code

@randomizedcoder
randomizedcoder force-pushed the bootstrap-read-header-timeout branch from b4a5428 to 950fed8 Compare July 20, 2026 21:52
@randomizedcoder
randomizedcoder marked this pull request as ready for review July 20, 2026 21:52
@SuperQ
SuperQ requested a review from nicolastakashi July 23, 2026 06:16
Comment thread bootstrap/bootstrap.go Outdated

// serverReadHeaderTimeout bounds request-header reads to mitigate Slowloris
// (gosec G112). Package var so tests can shorten it.
var serverReadHeaderTimeout = time.Minute

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Rather than a package-level var (only overridable by this package's own tests), I'd consider adding a ReadHeaderTimeout time.Duration field to Config, defaulting to time.Minute when unset, that matches how the rest of Config is configured (plain struct fields, not functional options) and lets downstream exporters tune it too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolastakashi Good idea! Thanks

@randomizedcoder
randomizedcoder force-pushed the bootstrap-read-header-timeout branch 4 times, most recently from cdc4a37 to 59d9579 Compare July 23, 2026 15:58
@nicolastakashi

Copy link
Copy Markdown
Contributor

@SuperQ LGTM, waiting for your final review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds configurable HTTP request-header timeouts to harden bootstrap-based exporters against Slowloris attacks.

Changes:

  • Defaults ReadHeaderTimeout to one minute.
  • Allows positive timeout overrides through bootstrap.Config.
  • Adds configuration and end-to-end timeout tests.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
bootstrap/bootstrap.go Configures the server header-read timeout.
bootstrap/bootstrap_test.go Tests timeout mapping and stalled connections.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread bootstrap/bootstrap.go
Comment on lines +89 to +91
// ReadHeaderTimeout bounds request-header reads, mitigating Slowloris
// (gosec G112). Defaults to one minute when zero.
ReadHeaderTimeout time.Duration

@ArthurSens ArthurSens left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM once the co-pilot nit is fixed :)

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>
@randomizedcoder
randomizedcoder force-pushed the bootstrap-read-header-timeout branch from 59d9579 to ab92444 Compare August 24, 2026 21:33
@randomizedcoder

randomizedcoder commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

@ArthurSens Thanks for the feedback. Addressed

I'd also love a review on: #396

@ArthurSens
ArthurSens merged commit 97c0308 into prometheus:master Aug 25, 2026
6 checks passed
@ArthurSens

Copy link
Copy Markdown
Member

Thanks, I'll try to take a look at the linked issue once I find some time 😭

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.

4 participants