fix: validate header name and value in webRequest.onBeforeSendHeaders (#51366)

* fix: validate header name and value in webRequest.onBeforeSendHeaders

Chromium's net::HttpRequestHeaders::SetHeader() uses CHECK() to enforce
valid header names and values, which causes a fatal crash if the caller
passes invalid strings. When users modify requestHeaders in the
onBeforeSendHeaders callback with invalid header names (e.g. containing
spaces) or invalid header values (e.g. containing CRLF), the
gin::Converter<net::HttpRequestHeaders>::FromV8() calls SetHeader()
directly, triggering the CHECK and crashing the process.

This change adds pre-validation using net::HttpUtil::IsValidHeaderName()
and net::HttpUtil::IsValidHeaderValue() before calling SetHeader(),
silently skipping invalid headers instead of crashing.

Co-authored-by: loufulton <loufulton.cz@gmail.com>

* Update shell/common/gin_converters/net_converter.cc

Co-authored-by: Charles Kerr <charles@charleskerr.com>

Co-authored-by: loufultoncz-coder <loufulton.cz@gmail.com>

* Update spec/api-web-request-spec.ts

Co-authored-by: Charles Kerr <charles@charleskerr.com>

Co-authored-by: loufultoncz-coder <loufulton.cz@gmail.com>

* fix: lint

Co-authored-by: loufulton <loufulton.cz@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: loufulton <loufulton.cz@gmail.com>
This commit is contained in:
trop[bot]
2026-04-28 11:52:40 -04:00
committed by GitHub
parent 04daf94c06
commit d7126ad027
2 changed files with 24 additions and 1 deletions

View File

@@ -253,8 +253,10 @@ bool Converter<net::HttpRequestHeaders>::FromV8(v8::Isolate* isolate,
if (!ConvertFromV8(isolate, val, &dict))
return false;
for (const auto it : dict) {
if (it.second.is_string())
if (it.second.is_string() && net::HttpUtil::IsValidHeaderName(it.first) &&
net::HttpUtil::IsValidHeaderValue(it.second.GetString())) {
out->SetHeader(it.first, std::move(it.second).TakeString());
}
}
return true;
}

View File

@@ -411,6 +411,27 @@ describe('webRequest module', () => {
expect(called).to.be.true();
});
it('does not crash on invalid header name or value', async () => {
ses.webRequest.onBeforeSendHeaders((details, callback) => {
const requestHeaders = details.requestHeaders;
requestHeaders['Invalid Header'] = 'valid-value';
requestHeaders['Valid-Header'] = 'invalid\r\nvalue';
requestHeaders['X-Good'] = 'good-value';
callback({ requestHeaders });
});
const sentHeaders = new Promise<Electron.OnSendHeadersListenerDetails>((resolve) => {
ses.webRequest.onSendHeaders(resolve);
});
const { data } = await ajax(defaultURL);
const details = await sentHeaders;
expect(details.requestHeaders['Invalid Header']).to.be.undefined();
expect(details.requestHeaders['Valid-Header']).to.be.undefined();
expect(details.requestHeaders['X-Good']).to.equal('good-value');
expect(data).to.equal('/');
});
it('resets the whole headers', async () => {
const requestHeaders = {
Test: 'header'