Add --header CLI flag for custom HTTP headers on verification requests#4950
Add --header CLI flag for custom HTTP headers on verification requests#4950infraguard-web wants to merge 2 commits into
Conversation
Closes trufflesecurity#3138. Adds a repeatable --header "Name: value" flag that injects custom HTTP headers into every detector verification request. Useful for proxy/WAF authentication, scanner identification at WAFs/SOCs, correlation tagging, and similar cross-cutting needs. The parser is extracted to pkg/common/header_parse.go with table-driven tests. Names and values are validated with httpguts at startup; malformed entries fail fast rather than silently dropping. Empty values are permitted per RFC 7230. Coverage spans the three HTTP architectures detectors use: 1. Shared HTTP client (most detectors): CustomTransport and detectorTransport call common.ApplyCustomHeaders during RoundTrip. ApplyCustomHeaders uses Set on the first value and Add on the rest so single-value user headers fully override transport defaults (e.g. User-Agent). AtomicHeader.Load returns a defensive clone. 2. Stdlib HTTP defaults / x/oauth2 fallthrough: detectors using http.DefaultClient, transport-less http.Client constructions, or oauth2.Transport with a nil Base read http.DefaultTransport at request time. main.go wraps DefaultTransport with CustomTransport at startup, but only when --header is set, so default behavior is unchanged for users not using the flag. 3. aws-sdk-go-v2: the AWS SDK builds its own complete transport stack and ignores http.DefaultTransport. Coverage is provided by an applyCustomHeadersMiddleware Smithy middleware on the STS and SNS verification clients, mirroring the existing replaceUserAgentMiddleware pattern. TestNoStdlibHTTPBypassInDetectors walks pkg/detectors and fails the build if a detector uses http.DefaultClient or stdlib convenience functions. The test caught one existing bypass in pkg/detectors/html2pdf which is patched to use http.NewRequestWithContext + common.SaneHttpClient().Do (also gives the detector proper context propagation it had been missing). pkg/detectors/readme/readme.go is switched from http.DefaultClient to detectors.DetectorHttpClientWithNoLocalAddresses, routing through the shared transport so it honors --header and closing an SSRF avenue on the verification path. The --header help text and regenerated man page include a warning that headers are sent to every verification endpoint; users should not configure target-scoped credentials via this mechanism.
|
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Reviewed by Cursor Bugbot for commit 5e61bfd. Configure here.
| // see no behavior change. SDK clients that build their own complete | ||
| // transport stack (notably aws-sdk-go-v2) bypass this and require | ||
| // SDK-level injection; see common/aws_middleware.go. | ||
| http.DefaultTransport = common.NewCustomTransport(http.DefaultTransport) |
There was a problem hiding this comment.
Double-wrapped CustomTransport duplicates User-Agent header
Medium Severity
When --header is set, http.DefaultTransport is replaced with a CustomTransport. Subsequently, any call to NewCustomTransport(nil) (which falls through to http.DefaultTransport) creates a nested CustomTransport wrapping another CustomTransport. Each layer calls req.Header.Add("User-Agent", ...), producing duplicate User-Agent values on the wire. This affects the new huggingface/client.go code and existing runtime callers like RetryableHTTPClientTimeout used by GitHub and CircleCI sources.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 5e61bfd. Configure here.


Description
Closes #3138.
Adds a repeatable
--header "Name: value"CLI flag that injects custom HTTP headers into every detector verification request. Useful for proxy/WAF authentication, scanner identification at WAFs/SOCs, correlation/telemetry tagging, and other cross-cutting needs that require headers on outbound verification traffic.Usage
The flag is repeatable. Format must be
Name: value(curl-style). Names and values are validated at startup withhttpguts.ValidHeaderFieldName/ValidHeaderFieldValue; malformed entries cause the binary to exit with a clear error rather than silently dropping. Empty values are permitted per RFC 7230. Empty names are rejected.Architecture
Detectors use one of three HTTP patterns. All three are covered:
Shared HTTP client (most detectors). The existing
CustomTransportanddetectorTransportalready wrap everyRoundTrip; they now call a sharedcommon.ApplyCustomHeaders(req)helper that injects user-configured headers. To avoid stacking on User-Agent and other transport-set defaults,ApplyCustomHeadersusesSeton the first value of each name andAddon subsequent values, giving single-value user headers true override semantics.AtomicHeader.Loadreturns a defensive clone of the configured headers so callers cannot mutate the shared map and race with other readers.Stdlib HTTP defaults and
x/oauth2fallthrough. Detectors that usehttp.DefaultClient, transport-less&http.Client{}constructions, oroauth2.Transportwith a nilBasereadhttp.DefaultTransportat request time.main.gowrapsDefaultTransportwithCustomTransportat startup, but only when--headeris set, so users not using the flag see no default-behavior change. This single change replaces what would otherwise be per-detector edits.aws-sdk-go-v2. The AWS SDK builds its own complete transport stack and ignoreshttp.DefaultTransport. Coverage is provided byapplyCustomHeadersMiddleware, a Smithy Build-phase middleware registered on the STS (verifyMatch) and SNS (verifyCanary) clients inpkg/detectors/aws/access_keys. It mirrors the placement and pattern of the existingreplaceUserAgentMiddleware.Supporting changes
pkg/detectors/readme/readme.goswitches fromhttp.DefaultClienttodetectors.DetectorHttpClientWithNoLocalAddresses. Routes through the shared transport (so it honors--header) and closes an SSRF avenue on the verification path.pkg/detectors/html2pdf/html2pdf.goreplaceshttp.Post(...)withhttp.NewRequestWithContext+common.SaneHttpClient().Do. Routes through the shared transport and gives the verifier proper context propagation it had been missing.Regression prevention
pkg/detectors/transport_audit_test.go(TestNoStdlibHTTPBypassInDetectors) walkspkg/detectors/**/*.goand fails the build if any non-test source useshttp.DefaultClient,http.Get,http.Post,http.Head, orhttp.PostForm. TheallowlistedFilesmap is a documented extension point for future SDK-managed exceptions (currently empty — the AWS middleware path doesn't match the regex patterns).Tests
=separatorApplyCustomHeaderstest covering no-op, single-value override, multi-value Set-then-Add, andLoad-clone safetyhttptest.NewServertest confirming custom headers reach the wire throughCustomTransportHTTPClientthat captures the outbound request — verifies headers reach the wire through the middleware stack without requiring real AWS credentialsManually verified through Burp Suite against three representative verifiers covering all three architectures: Jotform (shared client), Onelogin US + EU (
DefaultTransportwrap path), and AWS STS (SDK middleware). All four captures showed both custom headers reaching the wire;User-Agentstayed single-valued.Trade-offs called out
http.DefaultTransportmutation at startup. Mutating a Go global is generally a smell; here it is gated behind--headerbeing set, executed once after flag parse inmain.go, and clearly commented. The alternative — routing everyhttp.Clientconstruction site through a shared helper — would be much more invasive. Open to changing the approach if maintainers prefer.--headervalues. Silent skip would let pipeline misconfigurations propagate to production verifications; failing loud at startup matches what users would expect from a security tool. If maintainers want a--header-best-effortstyle escape hatch, easy to add.The flag's help entry (and regenerated man page) explicitly warn that custom headers travel to every verification endpoint, including external SaaS, so users should not configure credentials scoped to a single target via
--header.Checklist:
make test-community)?make lintthis requires golangci-lint)?Note
Medium Risk
Adds global injection of user-specified HTTP headers into verification traffic (including wrapping
http.DefaultTransport) and extends AWS SDK middleware, which could affect outbound request behavior across many detectors if misconfigured.Overview
Adds a repeatable
--header "Name: value"CLI flag and man-page docs to attach custom HTTP headers to all detector verification requests, with startup-time validation and a hard fail on malformed entries.Implements global header storage (
feature.CustomHeaders) and applies it in shared HTTP transports (common.CustomTransportanddetectorstransport) with override semantics (first valueSet, subsequentAdd), plus conditionally wrapshttp.DefaultTransportat startup when--headeris provided to catch stdlib-default clients.Extends coverage to non-stdlib paths by injecting headers into AWS
aws-sdk-go-v2verification calls via Smithy middleware, updates a couple of detectors to use the shared HTTP clients (e.g.,readme,html2pdf), and adds tests (header parsing, transport/header propagation, AWS middleware) plus a detectors audit test to prevent future direct use of stdlib HTTP helpers that would bypass the shared transport chain.Reviewed by Cursor Bugbot for commit 5e61bfd. Bugbot is set up for automated code reviews on this repo. Configure here.