From 3fce2cdc7a352f09ef325b7db235bfa63588cf61 Mon Sep 17 00:00:00 2001 From: fullsend-code <278716306+fullsend-ai-coder[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 11:50:54 +0000 Subject: [PATCH 1/2] docs(#376): add secure HTTP client guidance to AGENTS.md Add a "Secure HTTP clients" subsection under "Go code" documenting required security properties for outbound HTTP clients. Points agents to the SSRF-hardened fetch package (internal/fetch/) and lists the mandatory protections when a custom client is needed: HTTPS-only, DNS pre-resolution with IP validation via netutil, IP-pinned DialContext, redirect blocking, explicit timeout, and response size limiting. Prohibits http.Get and http.DefaultClient for external URLs from configuration or user input. Closes #376 --- AGENTS.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 5620b735fd..d5879b05d8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,6 +46,24 @@ The e2e tests require GitHub credentials. There are three ways to provide them: If only `E2E_GITHUB_USERNAME` and a password source are available, `make e2e-test` will automatically generate a session file before running tests. See `make help` for all available targets. +### Secure HTTP clients + +**Use the `fetch` package.** `internal/fetch/` provides an SSRF-hardened HTTP client (`FetchURL`). New code that fetches external URLs should use it rather than building a custom `http.Client`. + +**If you must build a custom client**, these properties are required: + +- **HTTPS-only** — reject `http://` URLs. +- **DNS pre-resolution with IP validation** — resolve the hostname and validate the IP using `netutil.IsInternal()` / `netutil.CheckIP()` from `internal/netutil/` to reject loopback, link-local, private, and other reserved addresses. +- **IP-pinned `DialContext`** — use a custom `DialContext` that dials the pre-validated IP to prevent DNS rebinding between resolution and connection. +- **Redirect blocking** — set `CheckRedirect` to block redirects entirely or validate that redirects stay HTTPS-only and pass IP validation. +- **Explicit timeout** — 30 s default; never leave the zero value. +- **Response body limit** — wrap response bodies with `io.LimitReader` (10 MB default). +- **Domain allowlisting** — when the set of valid hosts is known, restrict to that set. + +**Canonical implementation:** `internal/fetch/fetch.go` (`FetchURL`) and `internal/netutil/ip.go` (`CheckIP`, `IsInternal`). + +**Prohibited patterns:** Do not use `http.Get`, `http.DefaultClient`, or `&http.Client{}` with no timeout or SSRF protections for any code that contacts URLs from configuration or user input. + ## Forge abstraction All git forge operations (GitHub API calls, PR comments, issue creation, workflow dispatch, etc.) **must** go through the `forge.Client` interface defined in `internal/forge/forge.go`. This is a fundamental architectural rule — the codebase supports multiple forges (GitHub, GitLab, Forgejo) and direct coupling to any single forge breaks the abstraction. From 8d10b3bcc4042f623f97cb15c41782f323a168d5 Mon Sep 17 00:00:00 2001 From: fullsend-fix <278716306+fullsend-ai-coder[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 13:58:11 +0000 Subject: [PATCH 2/2] docs(#376): address review feedback on secure HTTP client guidance - Add Transport.Proxy bullet to custom-client checklist (proxy omission) - Fix bold formatting to use label-colon pattern for consistency Addresses review feedback on #421 --- AGENTS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d5879b05d8..d6a9acf382 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,9 +48,9 @@ If only `E2E_GITHUB_USERNAME` and a password source are available, `make e2e-tes ### Secure HTTP clients -**Use the `fetch` package.** `internal/fetch/` provides an SSRF-hardened HTTP client (`FetchURL`). New code that fetches external URLs should use it rather than building a custom `http.Client`. +**Use the `fetch` package:** `internal/fetch/` provides an SSRF-hardened HTTP client (`FetchURL`). New code that fetches external URLs should use it rather than building a custom `http.Client`. -**If you must build a custom client**, these properties are required: +**If you must build a custom client:** these properties are required: - **HTTPS-only** — reject `http://` URLs. - **DNS pre-resolution with IP validation** — resolve the hostname and validate the IP using `netutil.IsInternal()` / `netutil.CheckIP()` from `internal/netutil/` to reject loopback, link-local, private, and other reserved addresses. @@ -59,6 +59,7 @@ If only `E2E_GITHUB_USERNAME` and a password source are available, `make e2e-tes - **Explicit timeout** — 30 s default; never leave the zero value. - **Response body limit** — wrap response bodies with `io.LimitReader` (10 MB default). - **Domain allowlisting** — when the set of valid hosts is known, restrict to that set. +- **Disable proxy** — set `Transport.Proxy` to `nil` to prevent requests from being routed through `HTTP_PROXY`/`HTTPS_PROXY` environment variables. **Canonical implementation:** `internal/fetch/fetch.go` (`FetchURL`) and `internal/netutil/ip.go` (`CheckIP`, `IsInternal`).