From 21bbd667869df2442d2110ac57ff12de0d2bbbca Mon Sep 17 00:00:00 2001 From: wwhsaber Date: Thu, 16 Jul 2026 10:02:22 +0800 Subject: [PATCH] fix: prevent crash when Node rejects Set-Cookie header Clear pending request states before recovering from a failed response so the error path does not re-apply invalid cookie values that Node already rejected (ERR_INVALID_CHAR). Previously this looped and crashed the process. Closes #4527 --- lib/transmit.js | 7 +++++++ test/state.js | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/transmit.js b/lib/transmit.js index dafd2e369..aff4ffbb2 100755 --- a/lib/transmit.js +++ b/lib/transmit.js @@ -29,6 +29,13 @@ exports.send = async function (request) { } catch (err) { Bounce.rethrow(err, 'system'); + + // Drop pending states so the error response does not re-apply Set-Cookie + // values that Node already rejected (e.g. non-ASCII cookie values that + // pass statehood validation but fail res.setHeader). Re-emitting them + // would crash again inside fail() without a recovery path (#4527). + + request._states = {}; request._setResponse(err); return internals.fail(request, err); } diff --git a/test/state.js b/test/state.js index b6842342f..e1da02022 100755 --- a/test/state.js +++ b/test/state.js @@ -236,4 +236,27 @@ describe('state', () => { expect(res.statusCode).to.equal(500); expect(res.request.response._error).to.be.an.error('Partitioned cookies must have SameSite=None'); }); + + it('returns 500 without crashing when a cookie value is rejected by Node', async () => { + + // Non-ASCII cookie values pass statehood's strictHeader regex but Node's + // setHeader rejects them (ERR_INVALID_CHAR). The error path must not + // re-apply the same Set-Cookie or the process crashes (#4527). + + const server = Hapi.server({ debug: false }); + server.route({ + method: 'GET', + path: '/', + handler: (request, h) => h.response('ok').state('cookieName2', 'ั‚ะตัั‚') + }); + + const res = await server.inject('/'); + expect(res.statusCode).to.equal(500); + expect(res.headers['set-cookie']).to.not.exist(); + expect(res.result).to.equal({ + statusCode: 500, + error: 'Internal Server Error', + message: 'An internal server error occurred' + }); + }); });