fix(security): bound response bodies in secureFetchWithPinnedIP by default (#6169)

secureFetchWithPinnedIP only capped a response body when the caller passed
maxResponseBytes; with the option absent the body streamed into an unbounded
Buffer.concat. Several tool proxies whose target host is user-supplied
(Jupyter, ClickHouse, Grafana, 1Password Connect) and the RSS poller called it
without that option, so an attacker-controlled server answering with an endless
chunked body could grow the shared process heap until it was OOM-killed.

Make the cap fail-safe: default to 100MB (and treat a non-positive value as the
default) so there is no unlimited mode, then pass tighter explicit caps at the
user-supplied-host sites.

Responses that carry no body (HEAD, 204, 304) are exempted from the
content-length pre-check — they advertise the resource size as metadata, which
would otherwise spuriously fail a HEAD probe of a large file or an RSS
conditional-GET 304.
This commit is contained in:
Waleed
2026-08-01 16:54:34 -07:00
committed by GitHub
parent 47e8f1eb5b
commit d89ab4a8ee
13 changed files with 183 additions and 9 deletions
@@ -29,6 +29,8 @@ export const inputValidationMockFns = {
* ```
*/
export const inputValidationMock = {
DEFAULT_MAX_RESPONSE_BYTES: 100 * 1024 * 1024,
MAX_JSON_API_RESPONSE_BYTES: 10 * 1024 * 1024,
validateUrlWithDNS: inputValidationMockFns.mockValidateUrlWithDNS,
validateAndPinProxyUrl: inputValidationMockFns.mockValidateAndPinProxyUrl,
validateDatabaseHost: inputValidationMockFns.mockValidateDatabaseHost,