René's URL Explorer Experiment


Title: tls: server getPeerCertificate(true) drops the peer certificate chain since v26.8.0 (regressed by #64677) · Issue #65579 · nodejs/node · GitHub

Open Graph Title: tls: server getPeerCertificate(true) drops the peer certificate chain since v26.8.0 (regressed by #64677) · Issue #65579 · nodejs/node

X Title: tls: server getPeerCertificate(true) drops the peer certificate chain since v26.8.0 (regressed by #64677) · Issue #65579 · nodejs/node

Description: Version v26.8.0 and up. v26.7.0 is unaffected. Reproduces on current main. Platform Linux 6.18.35.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux Also reproduced on GitHub Actions ubuntu-latest. OpenSSL is 3.5.7. Subsys...

Open Graph Description: Version v26.8.0 and up. v26.7.0 is unaffected. Reproduces on current main. Platform Linux 6.18.35.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux Also reproduced on GitHub Actions...

X Description: Version v26.8.0 and up. v26.7.0 is unaffected. Reproduces on current main. Platform Linux 6.18.35.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux Also reproduced on GitHub Actions...

Opengraph URL: https://github.com/nodejs/node/issues/65579

X: @github

direct link

Domain: github.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"tls: server getPeerCertificate(true) drops the peer certificate chain since v26.8.0 (regressed by #64677)","articleBody":"### Version\n\n`v26.8.0` and up. `v26.7.0` is unaffected. Reproduces on current `main`.\n\n### Platform\n\n```text\nLinux 6.18.35.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux\n```\n\nAlso reproduced on GitHub Actions `ubuntu-latest`. OpenSSL is 3.5.7.\n\n### Subsystem\n\ntls\n\n### What steps will reproduce the bug?\n\nOn the server side of a mutual-TLS connection, `socket.getPeerCertificate(true)` no longer returns the client certificate's issuer chain. The leaf is returned fully populated, but `issuerCertificate` is `undefined`, even though the client presented `[leaf, intermediate]` and the socket is `authorized`.\n\nHere is a repo script that creates a root -> intermediate -> client chain with `openssl`, then runs a `node:https` mTLS handshake and reads the peer certificate on the server:\n\n```js\nimport https from 'node:https';\nimport { execFileSync } from 'node:child_process';\nimport { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\n// Generate root CA -> intermediate CA -> client leaf and server cert\nconst dir = mkdtempSync(join(tmpdir(), 'mtls-'));\nconst f = (n) => join(dir, n);\nconst openssl = (...a) => execFileSync('openssl', a, { stdio: 'ignore' });\nconst ec = ['-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:prime256v1', '-nodes'];\n\nopenssl('req', '-x509', ...ec, '-keyout', f('root.key'), '-out', f('root.crt'),\n  '-days', '2', '-subj', '/CN=Repro Root CA', '-addext', 'basicConstraints=critical,CA:TRUE');\n\nwriteFileSync(f('int.ext'), 'basicConstraints=critical,CA:TRUE,pathlen:0\\nkeyUsage=critical,keyCertSign,cRLSign\\n');\nopenssl('req', ...ec, '-keyout', f('int.key'), '-out', f('int.csr'), '-subj', '/CN=Repro Intermediate CA');\nopenssl('x509', '-req', '-in', f('int.csr'), '-CA', f('root.crt'), '-CAkey', f('root.key'),\n  '-CAcreateserial', '-days', '2', '-extfile', f('int.ext'), '-out', f('int.crt'));\n\nwriteFileSync(f('leaf.ext'), 'basicConstraints=critical,CA:FALSE\\nkeyUsage=critical,digitalSignature\\nextendedKeyUsage=clientAuth\\n');\nopenssl('req', ...ec, '-keyout', f('leaf.key'), '-out', f('leaf.csr'), '-subj', '/CN=Repro Client');\nopenssl('x509', '-req', '-in', f('leaf.csr'), '-CA', f('int.crt'), '-CAkey', f('int.key'),\n  '-CAcreateserial', '-days', '2', '-extfile', f('leaf.ext'), '-out', f('leaf.crt'));\n\nopenssl('req', '-x509', ...ec, '-keyout', f('srv.key'), '-out', f('srv.crt'),\n  '-days', '2', '-subj', '/CN=localhost', '-addext', 'subjectAltName=DNS:localhost');\n\nconst root = readFileSync(f('root.crt'));\nconst clientChain = Buffer.concat([readFileSync(f('leaf.crt')), readFileSync(f('int.crt'))]);\n\nconst server = https.createServer(\n  { key: readFileSync(f('srv.key')), cert: readFileSync(f('srv.crt')), ca: [root],\n    requestCert: true, rejectUnauthorized: false },\n  (req, res) => {\n    const cert = req.socket.getPeerCertificate(true);\n    console.log('node', process.version, '| authorized:', req.socket.authorized,\n                '| issuerCertificate present:', !!cert.issuerCertificate);\n    res.writeHead(200); res.end('x');\n  });\nserver.listen(0, 'localhost', () => {\n  const req = https.request(\n    { hostname: 'localhost', port: server.address().port,\n      key: readFileSync(f('leaf.key')), cert: clientChain, ca: [root], rejectUnauthorized: false },\n    (res) => { res.resume(); res.on('end', () => { server.close(); rmSync(dir, { recursive: true, force: true }); }); });\n  req.end();\n});\n```\n\nCompare output on an affected and an unaffected version:\n\n```\n$ node-v26.7.0 repro.mjs\nnode v26.7.0 | authorized: true | issuerCertificate present: true\n$ node-v26.8.1 repro.mjs\nnode v26.8.1 | authorized: true | issuerCertificate present: false\n```\n\n### How often does it reproduce? Is there a required condition?\n\nEvery time on Node >= 26.8.0. Requires `requestCert: true`, a client certificate signed through at least one intermediate, and reading the chain with `getPeerCertificate(true)` or `getPeerCertificate` with `includeChain`.\n\n### What is the expected behavior? Why is that the expected behavior?\n\n`getPeerCertificate(true)` on the server should return the leaf with an `issuerCertificate` property linking to the intermediate (and so on up the chain), as it did through v26.7.0 and as [documented](https://nodejs.org/api/tls.html#tlssocketgetpeercertificatedetailed): \"If the full certificate chain was requested, each certificate will include an `issuerCertificate` property containing an object representing its issuer's certificate.\"\n\n### What do you see instead?\n\nThe leaf is returned fully populated (subject, issuer, `raw`, fingerprints, etc.) but `issuerCertificate` is `undefined`. `getPeerX509Certificate().issuerCertificate` is also absent.\n\n### Additional information\n\nI bisected nightly builds and `v27.0.0-nightly20260808` (`aed4eaf89d`) is the last one before the break; `v27.0.0-nightly20260809` (`0700e749eb`) is where it breaks. The only tls/crypto commit in that range is c59cd6b04 (#64677), \"tls: fix authorized state on no-cert TLS1.3 client cert resumption\", which added to `onServerSocketSecure()` in `lib/internal/tls/wrap.js`.\n\nCalling `getPeerX509Certificate()` caches the peer certificate as a leaf only, so subsequent `getPeerCertificate(true)` returns the cached leaf only.\n\nThe underlying issue is really a caching interaction that predates #64677, which is that calling `getPeerX509Certificate()` poisons `getPeerCertificate(true)`. It can be reproduced on the unaffected versios by inserting that call before reading the chain, i.e., insert `req.socket.getPeerX509Certificate();` as the first line of the request handler in the repro above. #64677 tripped this by calling `getPeerX509Certificate()` internally.\n\nThere are sort of two issues here AFAICT: the caching interaction where `getPeerX509Certificate()` mutates the chain for a later `getPeerCertificate(true)`, and #64677 using `getPeerX509Certificate()` just to test presence of a peer certificate (instead of a check that does not populate/replace the cached peer certificate).\n\nThis regression affects any server that inspects the client certificate chain on Node >= 26.8.0.","author":{"url":"https://github.com/tgies","@type":"Person","name":"tgies"},"datePublished":"2026-08-27T09:47:45Z","url":"https://github.com/nodejs/node/issues/65579"}

react-profiling0
react-import-mapreact,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf
route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:2ed3cbe9-c93d-46ff-99be-28efd1d0f5ff
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-idCAA6:1C7D35:8DA0ED:BC5FC9:6AED2AA3
html-safe-nonce5f7b60ae5fbd3725afd09a31c0f8355ad6e4607fb4c21e3fa954ccc8c293024f
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDQUE2OjFDN0QzNTo4REEwRUQ6QkM1RkM5OjZBRUQyQUEzIiwidmlzaXRvcl9pZCI6Ijg2NDE2NTA1MjU4OTg3NzkyMyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9
visitor-hmacd41b3a30b80ce57cd6c9dc00e253576a03514d5c15a91e34e8874a0deff63a22
hovercard-subject-tagissue:5266181486
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/nodejs/node/65579/issue_layout
twitter:imagehttps://opengraph.githubassets.com/44ef0bdb93865f5499f373ec0f6ec0a7a8f3417820c0ad226d30e6e332305478/nodejs/node/issues/65579
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/44ef0bdb93865f5499f373ec0f6ec0a7a8f3417820c0ad226d30e6e332305478/nodejs/node/issues/65579
og:image:altVersion v26.8.0 and up. v26.7.0 is unaffected. Reproduces on current main. Platform Linux 6.18.35.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux Also reproduced on GitHub Actions...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernametgies
hostnamegithub.com
expected-hostnamegithub.com
None9d95365dda0576efe9b71f45807595e396bd0ca9286fba5367a05048e6ddf8f2
turbo-cache-controlno-preview
go-importgithub.com/nodejs/node git https://github.com/nodejs/node.git
octolytics-dimension-user_id9950313
octolytics-dimension-user_loginnodejs
octolytics-dimension-repository_id27193779
octolytics-dimension-repository_nwonodejs/node
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id27193779
octolytics-dimension-repository_network_root_nwonodejs/node
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release98b41fa4b5635ceb45a4c54320fced73817ff290
ui-targetfull
theme-color#1e2327
color-schemelight dark
react-app-nameissues

Links:

Skip to contenthttps://github.com/nodejs/node/issues/65579#start-of-content
https://github.com/
Sign inhttps://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fnodejs%2Fnode%2Fissues%2F65579
GitHubRepository hosting, code review, and collaborationhttps://github.com/platform
CopilotAI coding agent for tasks, projects, and automated workhttps://github.com/features/copilot
ActionsCI/CD and automationhttps://github.com/features/actions
Code QualityQuality analysis, fixes, and enforcementhttps://github.com/features/code-quality
CodespacesCloud development environmentshttps://github.com/features/codespaces
Code SecurityVulnerability detection and remediationhttps://github.com/security/advanced-security/code-security
Secret ProtectionSecret scanning and leak preventionhttps://github.com/security/advanced-security/secret-protection
All Featureshttps://github.com/features
Documentationhttps://docs.github.com/en
Traininghttps://learn.github.com/skills
Certificationshttps://learn.github.com/credentials
Build with Copilothttps://github.com/features/ai
Customize Copilothttps://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/customize-copilot-overview
Integrationshttps://github.com/marketplace
Trending reposhttps://github.com/trending
GitHub Sponsorshttps://github.com/open-source/sponsors
Developer articleshttps://github.com/resources/articles
ChangelogYour source for the latest features, improvements, and fixes across GitHub products, all in one place.https://github.blog/changelog/
Enterpriseshttps://github.com/enterprise
Teamhttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
See all industrieshttps://github.com/solutions/industry
Why GitHubhttps://github.com/why-github
Customer Storieshttps://github.com/customer-stories
Business insightshttps://github.com/solutions/executive-insights
Trust Centerhttps://github.com/trust-center
GitHub Advanced SecurityEnterprise-grade code securityhttps://github.com/security/advanced-security
Copilot for businessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/enterprise/premium-support
Documentationhttps://docs.github.com/en
Resource centerhttps://github.com/resources
Bloghttps://github.blog/
Events & webinarshttps://github.com/resources/events
Community Forumhttps://github.com/orgs/community/discussions
Customer Storieshttps://github.com/customer-stories
Integrationshttps://github.com/marketplace
Customer supporthttps://help.github.com/
Traininghttps://learn.github.com/skills
GitHub Statushttps://www.githubstatus.com/
Abouthttps://github.com/about
Partnershttps://github.com/partners
Changeloghttps://github.blog/changelog/
GitHub UniverseThe event for developers, by developers — talks, workshops, and what’s next for GitHub.https://githubuniverse.com/
Pricinghttps://github.com/pricing
Sign inhttps://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fnodejs%2Fnode%2Fissues%2F65579
Sign uphttps://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=nodejs%2Fnode
Reloadhttps://github.com/nodejs/node/issues/65579
Reloadhttps://github.com/nodejs/node/issues/65579
Reloadhttps://github.com/nodejs/node/issues/65579
nodejshttps://github.com/nodejs
nodehttps://github.com/nodejs/node
Codehttps://github.com/nodejs/node
Issues656 (656)https://github.com/nodejs/node/issues
Pull requests666 (666)https://github.com/nodejs/node/pulls
Actionshttps://github.com/nodejs/node/actions
Projectshttps://github.com/nodejs/node/projects
Security and qualityhttps://github.com/nodejs/node/security
Insightshttps://github.com/nodejs/node/pulse
https://github.com/nodejs/node
New issuehttps://github.com/login?return_to=https://github.com/nodejs/node/issues/65579
New issuehttps://github.com/login?return_to=https://github.com/nodejs/node/issues/65579
#65602https://github.com/nodejs/node/pull/65602
tls: server getPeerCertificate(true) drops the peer certificate chain since v26.8.0 (regressed by #64677)https://github.com/nodejs/node/issues/65579#top
#65602https://github.com/nodejs/node/pull/65602
https://github.com/tgies
tgieshttps://github.com/tgies
on Aug 27, 2026https://github.com/nodejs/node/issues/65579#issue-5266181486
documentedhttps://nodejs.org/api/tls.html#tlssocketgetpeercertificatedetailed
c59cd6bhttps://github.com/nodejs/node/commit/c59cd6b046e7834b231ef68cb1e3efc0d38e9c5e
#64677https://github.com/nodejs/node/pull/64677
#64677https://github.com/nodejs/node/pull/64677
#64677https://github.com/nodejs/node/pull/64677
#64677https://github.com/nodejs/node/pull/64677
https://github.com/santusht06
santusht06https://github.com/santusht06
on Aug 27, 2026https://github.com/nodejs/node/issues/65579#issuecomment-5441995499
#64677https://github.com/nodejs/node/pull/64677
tgieshttps://github.com/tgies
on Aug 28, 2026https://github.com/nodejs/node/issues/65579#event-30146855085
test(mtls): guard the includeChain socket test against nodejs/node#65579https://github.com/tgies/client-certificate-auth/commit/8e8f79108511e3675d2f7178ba5d6c842e97d42f
nodejs/node#65579https://github.com/nodejs/node/issues/65579
8e8f791https://github.com/tgies/client-certificate-auth/commit/8e8f79108511e3675d2f7178ba5d6c842e97d42f
test(mtls): guard the includeChain socket test against nodejs/node#65579https://github.com/tgies/client-certificate-auth/commit/8f93499ab9d3dac88a0990db8a73924568558b29
nodejs/node#65579https://github.com/nodejs/node/issues/65579
8f93499https://github.com/tgies/client-certificate-auth/commit/8f93499ab9d3dac88a0990db8a73924568558b29
nodejs-github-bothttps://github.com/nodejs-github-bot
completedhttps://github.com/nodejs/node/issues?q=is%3Aissue%20state%3Aclosed%20archived%3Afalse%20reason%3Acompleted
#65602https://github.com/nodejs/node/pull/65602
on Aug 31, 2026https://github.com/nodejs/node/issues/65579#event-30296579109
nodejs-github-bothttps://github.com/nodejs-github-bot
on Aug 31, 2026https://github.com/nodejs/node/issues/65579#event-30296579120
tls: read the peer certificate chain without consuming ithttps://github.com/nodejs/node/commit/705646f2f70fd8097d13d85de8347a74b6c443af
705646fhttps://github.com/nodejs/node/commit/705646f2f70fd8097d13d85de8347a74b6c443af
aduh95https://github.com/aduh95
on Sep 3, 2026https://github.com/nodejs/node/issues/65579#event-30485769532
tls: read the peer certificate chain without consuming ithttps://github.com/nodejs/node/commit/714a7875eb905949353363d813e917714258c8a7
714a787https://github.com/nodejs/node/commit/714a7875eb905949353363d813e917714258c8a7
aduh95https://github.com/aduh95
on Sep 15, 2026https://github.com/nodejs/node/issues/65579#event-31161517859
tls: read the peer certificate chain without consuming ithttps://github.com/nodejs/node/commit/6a3d8a6d9f171525f9edf35f0c467c5688639f08
6a3d8a6https://github.com/nodejs/node/commit/6a3d8a6d9f171525f9edf35f0c467c5688639f08
tls: read the peer certificate chain without consuming ithttps://github.com/nodejs/node/commit/656116bf451a59254aaa8f2f798d67ebc3070396
656116bhttps://github.com/nodejs/node/commit/656116bf451a59254aaa8f2f798d67ebc3070396
tls: read the peer certificate chain without consuming ithttps://github.com/nodejs/node/commit/ffd3de28316c42179eeeda2402e55056bb1e8798
ffd3de2https://github.com/nodejs/node/commit/ffd3de28316c42179eeeda2402e55056bb1e8798
kriszyphttps://github.com/kriszyp
on Sep 25, 2026https://github.com/nodejs/node/issues/65579#event-31862091310
Reject mTLS clients whose revocation status cannot be checked under f…https://github.com/HarperFast/harper/commit/47c6029338ac1e75be80a3243554634e0c8a7091
47c6029https://github.com/HarperFast/harper/commit/47c6029338ac1e75be80a3243554634e0c8a7091
skynetigorhttps://github.com/skynetigor
on Oct 28, 2026https://github.com/nodejs/node/issues/65579#event-34477656084
Add PKI tests for client certificates issued by an intermediate CA (e…https://github.com/skynetigor/kibana/commit/4674bcc6b73230c0385374aa58de4d4fd4d11ff4
e…https://github.com/elastic/kibana/pull/300155
4674bcchttps://github.com/skynetigor/kibana/commit/4674bcc6b73230c0385374aa58de4d4fd4d11ff4
kibanamachinehttps://github.com/kibanamachine
on Oct 28, 2026https://github.com/nodejs/node/issues/65579#event-34482773262
[9.6] Add PKI tests for client certificates issued by an intermediate…https://github.com/elastic/kibana/commit/2a98ee3b0c8897ad6d11b08cd515fecdabac8e06
2a98ee3https://github.com/elastic/kibana/commit/2a98ee3b0c8897ad6d11b08cd515fecdabac8e06
Sign up for freehttps://github.com/signup?return_to=https://github.com/nodejs/node/issues/65579
Sign in to commenthttps://github.com/login?return_to=https://github.com/nodejs/node/issues/65579
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.