test(client-certificates): do not reuse a renegotiated connection - #42878
Merged
Yury Semikhatsky (yury-s) merged 1 commit intoSep 24, 2026
Merged
Yury Semikhatsky (yury-s) merged 1 commit into
Yury Semikhatsky (yury-s) merged 1 commit into
Conversation
Node counts server-initiated renegotiations against tls.CLIENT_RENEG_LIMIT, and the accounting is such that the second renegotiation on one socket already exceeds the default of 3: the socket is destroyed with "TLS session renegotiation attack detected" while the response is still being produced. This test renegotiates for both /from-fetch-api and /style.css, so it only survived when the two requests landed on different connections. That was up to the browser's connection pool. WebKit usually reuses the fetch connection for the following navigation, which retires it, and serves the stylesheet on a fresh socket; roughly once in fifteen runs the navigation opened a new connection instead, the stylesheet reused the renegotiated one, and the server killed it mid-request. The browser reported "The network connection was lost.", the stylesheet never arrived, and the button kept its default color. Close the connection after each response that renegotiates, so every renegotiation gets a socket of its own. This also makes the coverage deterministic: before, whether the stylesheet was fetched over a renegotiated connection depended on pooling; now both steps always renegotiate exactly once. The response is still chunked and gzip encoded, as the browser sees it.
Contributor
Test results for "tests 1"6 flaky52074 passed, 1241 skipped Merge workflow run. |
Contributor
Test results for "MCP"6 failed 8699 passed, 1474 skipped Merge workflow run. |
Contributor
Author
Yury Semikhatsky (yury-s)
approved these changes
Sep 24, 2026
| 'Transfer-Encoding': 'chunked' | ||
| 'Transfer-Encoding': 'chunked', | ||
| // A renegotiated connection must not be reused: a second renegotiation on | ||
| // the same socket trips Node's tls.CLIENT_RENEG_LIMIT and destroys it. |
There was a problem hiding this comment.
Brave new world!
Yury Semikhatsky (yury-s)
merged commit Sep 24, 2026
0d3f1b4
into
microsoft:main
44 of 45 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Node counts server-initiated renegotiations against tls.CLIENT_RENEG_LIMIT, and the accounting is such that the second renegotiation on one socket already exceeds the default of 3: the socket is destroyed with "TLS session renegotiation attack detected" while the response is still being produced.
This test renegotiates for both /from-fetch-api and /style.css, so it only survived when the two requests landed on different connections. That was up to the browser's connection pool. WebKit usually reuses the fetch connection for the following navigation, which retires it, and serves the stylesheet on a fresh socket; roughly once in fifteen runs the navigation opened a new connection instead, the stylesheet reused the renegotiated one, and the server killed it mid-request. The browser reported "The network connection was lost.", the stylesheet never arrived, and the button kept its default color.
Close the connection after each response that renegotiates, so every renegotiation gets a socket of its own. This also makes the coverage deterministic: before, whether the stylesheet was fetched over a renegotiated connection depended on pooling; now both steps always renegotiate exactly once. The response is still chunked and gzip encoded, as the browser sees it.