From 7749745cb9aad7b08103052aceb3ee8ee2b943ac Mon Sep 17 00:00:00 2001 From: thanik123789-coder Date: Tue, 10 Mar 2026 09:00:07 +0700 Subject: [PATCH 1/5] Fix #819: sanitize CN to prevent hang This PR fixes the indefinite hang issue (#819) by sanitizing SubjectCN and IssuerCN length and encoding. /claim #819 --- pkg/tlsx/clients/utils.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/tlsx/clients/utils.go b/pkg/tlsx/clients/utils.go index dd9bbc2b..0554ad41 100644 --- a/pkg/tlsx/clients/utils.go +++ b/pkg/tlsx/clients/utils.go @@ -28,9 +28,9 @@ func Convertx509toResponse(options *Options, hostname string, cert *x509.Certifi MisMatched: IsMisMatchedCert(hostname, domainNames), Revoked: IsTLSRevoked(options, cert), WildCardCert: IsWildCardCert(domainNames), - IssuerCN: cert.Issuer.CommonName, + IssuerCN: sanitizeCN(cert.Issuer.CommonName), IssuerOrg: cert.Issuer.Organization, - SubjectCN: cert.Subject.CommonName, + SubjectCN: sanitizeCN(cert.Subject.CommonName), SubjectOrg: cert.Subject.Organization, FingerprintHash: CertificateResponseFingerprintHash{ MD5: MD5Fingerprint(cert.Raw), @@ -153,3 +153,9 @@ func IsClientCertRequiredError(err error) bool { } return false } +func sanitizeCN(s string) string { + if len(s) > 256 { + s = s[:256] + } + return strings.ToValidUTF8(s, "") +} From eaae1f30823bb7729a2372515f6e631c711dfc5f Mon Sep 17 00:00:00 2001 From: thanik123789-coder Date: Tue, 10 Mar 2026 09:19:30 +0700 Subject: [PATCH 2/5] fix: update sanitizeCN to handle multi-byte characters (rune-aware) Updated sanitizeCN to use rune-aware truncation to prevent multi-byte character corruption as suggested by CodeRabbit. --- pkg/tlsx/clients/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/tlsx/clients/utils.go b/pkg/tlsx/clients/utils.go index 0554ad41..9030ba38 100644 --- a/pkg/tlsx/clients/utils.go +++ b/pkg/tlsx/clients/utils.go @@ -154,8 +154,8 @@ func IsClientCertRequiredError(err error) bool { return false } func sanitizeCN(s string) string { - if len(s) > 256 { - s = s[:256] + if len(runes) > 256 { + runes = runes[:256] } return strings.ToValidUTF8(s, "") } From f7045163835bfced20851d3dd6b32e400a30c95d Mon Sep 17 00:00:00 2001 From: thanik123789-coder Date: Tue, 10 Mar 2026 09:27:29 +0700 Subject: [PATCH 3/5] fix: return truncated string instead of original in sanitizeCN --- pkg/tlsx/clients/utils.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/tlsx/clients/utils.go b/pkg/tlsx/clients/utils.go index 9030ba38..aab149ca 100644 --- a/pkg/tlsx/clients/utils.go +++ b/pkg/tlsx/clients/utils.go @@ -154,8 +154,9 @@ func IsClientCertRequiredError(err error) bool { return false } func sanitizeCN(s string) string { + runes := []rune(s) if len(runes) > 256 { runes = runes[:256] } - return strings.ToValidUTF8(s, "") + return strings.ToValidUTF8(string(runes), "") } From 8febee12403740f9019c2c2dc58ce26c4fb32966 Mon Sep 17 00:00:00 2001 From: thanik123789-coder Date: Tue, 10 Mar 2026 09:55:39 +0700 Subject: [PATCH 4/5] Update utils.go --- pkg/tlsx/clients/utils.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/pkg/tlsx/clients/utils.go b/pkg/tlsx/clients/utils.go index aab149ca..f8163405 100644 --- a/pkg/tlsx/clients/utils.go +++ b/pkg/tlsx/clients/utils.go @@ -9,14 +9,17 @@ import ( "net" "strings" "time" - + "unicode/utf8" "github.com/projectdiscovery/utils/errkit" iputil "github.com/projectdiscovery/utils/ip" mapsutil "github.com/projectdiscovery/utils/maps" ) func Convertx509toResponse(options *Options, hostname string, cert *x509.Certificate, showcert bool) *CertificateResponse { - domainNames := []string{cert.Subject.CommonName} +subjectCN := sanitizeCN(cert.Subject.CommonName) + issuerCN := sanitizeCN(cert.Issuer.CommonName) + + domainNames := []string{cert.Subject.CommonName} domainNames = append(domainNames, cert.DNSNames...) response := &CertificateResponse{ SubjectAN: cert.DNSNames, @@ -154,9 +157,19 @@ func IsClientCertRequiredError(err error) bool { return false } func sanitizeCN(s string) string { - runes := []rune(s) - if len(runes) > 256 { - runes = runes[:256] + var b strings.builder + b.Grow(256*utf8.UTFMax) + count := 0 + for len(s)>0 && count<256 { + r, size := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && size == 1 { + s = s[1:] + continue + } + b.WriteRune(r) + s = s[size:] + count++ } - return strings.ToValidUTF8(string(runes), "") + + return b.String() } From 4773d4d38847aa951ef7a0d63c7701fd370a9bb4 Mon Sep 17 00:00:00 2001 From: thanik123789-coder Date: Tue, 10 Mar 2026 10:13:10 +0700 Subject: [PATCH 5/5] Update utils.go2 --- pkg/tlsx/clients/utils.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/tlsx/clients/utils.go b/pkg/tlsx/clients/utils.go index f8163405..429190d5 100644 --- a/pkg/tlsx/clients/utils.go +++ b/pkg/tlsx/clients/utils.go @@ -14,12 +14,12 @@ import ( iputil "github.com/projectdiscovery/utils/ip" mapsutil "github.com/projectdiscovery/utils/maps" ) - func Convertx509toResponse(options *Options, hostname string, cert *x509.Certificate, showcert bool) *CertificateResponse { subjectCN := sanitizeCN(cert.Subject.CommonName) issuerCN := sanitizeCN(cert.Issuer.CommonName) - - domainNames := []string{cert.Subject.CommonName} + + + domainNames := []string{subjectCN} domainNames = append(domainNames, cert.DNSNames...) response := &CertificateResponse{ SubjectAN: cert.DNSNames, @@ -31,9 +31,9 @@ subjectCN := sanitizeCN(cert.Subject.CommonName) MisMatched: IsMisMatchedCert(hostname, domainNames), Revoked: IsTLSRevoked(options, cert), WildCardCert: IsWildCardCert(domainNames), - IssuerCN: sanitizeCN(cert.Issuer.CommonName), + IssuerCN: issuerCN, IssuerOrg: cert.Issuer.Organization, - SubjectCN: sanitizeCN(cert.Subject.CommonName), + SubjectCN: subjectCN, SubjectOrg: cert.Subject.Organization, FingerprintHash: CertificateResponseFingerprintHash{ MD5: MD5Fingerprint(cert.Raw), @@ -157,8 +157,8 @@ func IsClientCertRequiredError(err error) bool { return false } func sanitizeCN(s string) string { - var b strings.builder - b.Grow(256*utf8.UTFMax) + var b strings.Builder + b.Grow(256 * utf8.UTFMax) count := 0 for len(s)>0 && count<256 { r, size := utf8.DecodeRuneInString(s)