diff --git a/services/network/public/cpp/header_util.cc b/services/network/public/cpp/header_util.cc index a75f986549382..de5b859670354 100644 --- a/services/network/public/cpp/header_util.cc +++ b/services/network/public/cpp/header_util.cc @@ -16,6 +16,7 @@ #include "net/base/mime_sniffer.h" #include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" +#include "net/http/http_util.h" #include "net/http/http_status_code.h" #include "services/network/public/cpp/features.h" #include "services/network/public/mojom/url_response_head.mojom.h" @@ -95,6 +96,28 @@ bool IsRequestHeaderSafe(std::string_view key, std::string_view value) { if (base::StartsWith(key, "Proxy-", base::CompareCase::INSENSITIVE_ASCII)) return false; + // Per https://fetch.spec.whatwg.org/#forbidden-request-header, the method- + // override headers are forbidden when their value parses to a forbidden + // method. A compromised renderer could otherwise smuggle a TRACE/TRACK + // request past CorsURLLoaderFactory's IsForbiddenMethod() gate. The same + // logic already exists in the renderer-side net::HttpUtil::IsSafeHeader(). + static constexpr const char* kMethodOverrideHeaders[] = { + "X-HTTP-Method", "X-HTTP-Method-Override", "X-Method-Override"}; + static constexpr const char* kForbiddenMethods[] = {"CONNECT", "TRACE", + "TRACK"}; + for (const char* header : kMethodOverrideHeaders) { + if (base::EqualsCaseInsensitiveASCII(header, key)) { + net::HttpUtil::ValuesIterator it(value, ','); + while (it.GetNext()) { + for (const char* method : kForbiddenMethods) { + if (base::EqualsCaseInsensitiveASCII(it.value(), method)) { + return false; + } + } + } + } + } + return true; }