Repository navigation
Hardening 2026-10: dependency upgrades, security & HTTP correctness fixes - #14
Merged
Merged
Conversation
fasthttp now uses molecule-man/go-brrr (pure Go) instead of andybalholm/brotli; CGO_ENABLED=0 and windows builds verified, govulncheck clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Accept-Encoding parsing
Start now loads and validates the TLS keypair with tls.X509KeyPair before opening any socket (OPS-002, replaces the panicking mustReadFile), binds listeners synchronously and returns bind errors directly, closing any listener already opened (OPS-001). Serve-loop errors after startup are delivered on Errors(); errors caused by Shutdown are suppressed. Listeners use "tcp" instead of "tcp4" so IPv6 and dual-stack addresses work (OPS-003). Listener fields are published under a mutex and exposed via HTTPAddr/HTTPSAddr, removing the data race on httpLn/httpsLn (OPS-004). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Validate rejects out-of-range or inconsistent settings (bad listen addresses, tls_cert without tls_key, negative timeouts/sizes, zero cache limits when caching is enabled, gzip level outside 1..9/-1, negative max-ages) and reports every problem at once (OPS-007). - Load returns an error for env vars that fail to parse instead of silently dropping them; booleans use strconv.ParseBool (OPS-005). - Load errors when a non-empty path does not exist (OPS-006). - Implement documented STATIC_SECURITY_HSTS_MAX_AGE, STATIC_SECURITY_DIRECTORY_LISTING and add STATIC_SECURITY_HSTS_INCLUDE_SUBDOMAINS (OPS-008). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- serve() returns an exit code; a Start error (port in use, bad TLS keypair) exits 1, and a serve loop dying later cancels the signal handler context and exits 1 (OPS-001). - An explicit --config that does not exist is an error; the implicit default config.toml remains optional (OPS-006). - Config is built by loadConfig (file, env, CLI flags, positional root, Validate) both at startup and on SIGHUP, so reloads no longer drop CLI overrides (OPS-009). RunSignalHandler takes a ReloadFunc, no longer panics with a nil cache, and logs what reload actually does. - parseBytes rejects sizes that overflow int64 (OPS-010). - helpText no longer prints a literal %% (OPS-011). - Sync embedded config.toml.example with the root example and test that they stay identical and valid (OPS-008). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep the documented tcp4 fast path for empty/IPv4 hosts but select "tcp" for IPv6 literals and hostnames so they no longer fail to bind (OPS-003). SO_REUSEPORT/TCP_NODELAY on Linux apply to both families. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CI runs on push to main and on pull_request only (no double runs), with per-ref concurrency. - Add gofmt, go mod tidy -diff, embedded config sync, and pinned staticcheck (v0.8.2) steps; pin govulncheck to v1.9.0. - Annotate action SHAs with exact versions (checkout v4.3.1, setup-go v5.6.0). - release.yml: default contents: read, contents: write scoped to the release job. - .goreleaser.yaml: drop the go mod tidy before-hook (CI enforces tidiness) and use v2 archives.format_overrides.formats. - Add weekly dependabot updates for gomod and github-actions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on, HEAD length parity
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
go.mod's `go 1.26.0` directive made setup-go pin Go 1.26.0, which has 31 known stdlib vulnerabilities (govulncheck failed). CI and release now use the newest stable release (check-latest); go.mod keeps the minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ersion Adds in-function Clean+HasPrefix containment checks before opening large files and sidecars (defense in depth; resolves CodeQL go/path-injection), opens sidecars once and size-checks the handle (no stat/read TOCTOU), and bounds the stream length before converting int64 to int (32-bit safety). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Dependency upgrades plus the fixes from a four-expert review panel (security, concurrency, HTTP semantics, SRE). The full plan and its status are in
docs/HARDENING_PLAN_2026-10.md. Each bug fix started with a regression test that failed by assertion.Dependencies
Security and data integrity
0-ranges used to build a 133 MB response for a 100 KB file. Ranges are now capped at 16, a request whose ranges add up to more than the file is ignored (200), and an unsatisfiable range returns 416 withContent-Range: bytes */N.index.htmlcould expose files outside the root, or dotfiles. Index paths now go throughPathSafe.PathCachecached results for paths that did not exist yet, so a later symlink could escape the root. Only paths that were verified to exist are cached now.HTTP correctness
Varytokens are merged into one header, soVary: Originis no longer dropped.Cache-Control,ETagandVary.If-Rangeis supported, and ETags are compared weakly.Allow, and 405 responses includeAllow.Accept-Encodingnames are matched case-insensitively and q-values are parsed as numbers.Robustness and operations
Config.Validate(). Invalid env values cause an error instead of being ignored, and an explicit--configpath must exist.tcp4is still used for IPv4, to keep the documented throughput.STATIC_SECURITY_HSTS_MAX_AGE,STATIC_SECURITY_DIRECTORY_LISTINGandSTATIC_SECURITY_HSTS_INCLUDE_SUBDOMAINS.go mod tidy -diffand a config-example diff check. Added Dependabot. Release permissions are now scoped to the release job.Behaviour changes
--config, now stop startup.Test plan
gofmt,go vet,go test -race ./..., staticcheck v0.8.2,go mod tidy -diff--configboth exit 1🤖 Generated with Claude Code