RedScore.ai

Fixes

Web Application Security · Updated 2026-05-02

SAN Hostname Match

Cert's SAN list must cover the hostname being served. Tied to Chain Completeness via the same verified-handshake flag.

SAN Hostname Match verifies that the certificate served by your host actually covers the hostname clients request. Modern certs use Subject Alternative Names (SANs) to list every hostname they are valid for; the legacy Common Name field is no longer trusted by browsers. If clients request api.yourdomain.tld but the served cert's SAN list is just [yourdomain.tld, www.yourdomain.tld], the handshake fails strict verification and this sub-weight scores zero.

Important coupling: this sub-weight and Chain Completeness share a single underlying signal (verified_chain_and_san_ok). If either fails, both fail in the same scan. To know which one is actually broken, inspect the cert manually with openssl.

How the check works

Per primary HTTPS host, RedScore performs a strict TLS handshake using the Python ssl module's default context (system trust store + hostname verification). The hostname is checked against the cert's SAN list. If the handshake succeeds end-to-end, both SAN Hostname Match and Chain Completeness pass (8 + 5 pts). If anything fails (chain not trusted, cert not for this hostname, expired root, etc.), both fail.

How the verdict maps to evidence

  • Pass (8/8 per host): strict TLS handshake succeeded; cert SAN covers the requested hostname.
  • Fail (0/8 per host): strict TLS handshake failed for any reason. The reason could be SAN mismatch, untrusted chain, expired cert, or other; the score does not differentiate.

Diagnose: inspect the cert's SAN list

Run openssl against your host and read the SAN list directly:

Read the cert's SAN list

openssl s_client -connect yourdomain.tld:443 -servername yourdomain.tld < /dev/null 2>/dev/null \
  | openssl x509 -noout -ext subjectAltName

# Output looks like:
# X509v3 Subject Alternative Name:
#     DNS:yourdomain.tld, DNS:www.yourdomain.tld, DNS:*.yourdomain.tld

Compare the DNS: entries to the actual hostname being requested. If the hostname is api.yourdomain.tld and the SAN list does not include api.yourdomain.tld or *.yourdomain.tld, that is the problem. Note that wildcards cover exactly one level: *.yourdomain.tld covers api.yourdomain.tld but does NOT cover dev.api.yourdomain.tld.

Fix: get a cert with proper SAN coverage

Single hostname or apex + www

Issue with both names listed. Most ACME clients accept multiple -d flags:

certbot

sudo certbot --nginx -d yourdomain.tld -d www.yourdomain.tld

Wildcard for one subdomain layer

If you have many subdomains under one parent (api, app, admin, dev, etc. all under yourdomain.tld), a wildcard for *.yourdomain.tld covers them all. Wildcards require DNS-01 validation in ACME because Let's Encrypt cannot HTTP-validate hostnames that do not exist yet.

Wildcard with certbot (DNS-01)

sudo certbot certonly --manual --preferred-challenges dns \
  -d yourdomain.tld -d "*.yourdomain.tld"

# Or with a DNS plugin (recommended for renewal):
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d yourdomain.tld -d "*.yourdomain.tld"

A single wildcard does NOT cover multiple subdomain levels. *.yourdomain.tld covers api.yourdomain.tld but not dev.api.yourdomain.tld. For deep subdomain trees, issue separate wildcards: *.yourdomain.tld and *.api.yourdomain.tld and *.dev.api.yourdomain.tld.

Multi-domain (SAN cert)

If you serve several different domains from one host (yourdomain.tld plus yourbrand.com plus partnerdomain.io), a multi-SAN cert covers all of them in one issuance:

Multi-SAN with certbot

sudo certbot --nginx \
  -d yourdomain.tld -d www.yourdomain.tld \
  -d yourbrand.com -d www.yourbrand.com \
  -d partnerdomain.io

Most ACME clients support up to 100 SANs per cert. If you go over that, split into multiple certs and route via SNI on the server.

Managed platforms

Vercel, Netlify, Cloudflare Pages, Render, Heroku, App Engine, etc. all handle SAN coverage automatically when you attach custom domains. If you see a SAN mismatch on a managed host, the custom domain was likely added to your account but the platform's auto-issuance has not finished yet (or DNS still points elsewhere). Check the platform's domain settings dashboard.

Verify the fix

  • Read the SAN list with the openssl command above. Confirm every primary HTTPS host appears in the list (or is covered by a wildcard).
  • openssl s_client -connect yourdomain.tld:443 -servername yourdomain.tld -verify_return_error < /dev/null. The -verify_return_error flag fails the handshake if verification does not pass; success means SAN, chain, and validity all check out.
  • ssllabs.com/ssltest reports SAN list and chain validation per probed host.
  • Re-run the RedScore lookup. Pass requires strict-verify success on every primary HTTPS host.

Common pitfalls

  • Wildcards only cover one level. *.yourdomain.tld matches api.yourdomain.tld but not deep.api.yourdomain.tld. Plan SAN coverage by tree depth.
  • Common Name without matching SAN. Browsers stopped trusting CN-only matches in 2017. Every hostname needs an entry in the SAN list, not just the CN.
  • Cert chosen by SNI does not match request host. If your server hosts multiple domains via SNI and the SNI handshake picks the wrong cert, SAN match fails. Verify with openssl s_client -servername to be sure the right cert is served.
  • Renewal added a hostname but did not include it in SAN. ACME clients use the -d flags from the renewal command. If the renewal config is missing a hostname, the new cert lacks that SAN. Inspect after each renewal.
  • Browser treats it as fine but the check fails. Some browsers tolerate slightly-broken SAN matches via fallback heuristics. The Python ssl module does strict verification, so the check is stricter than some browsers. Trust the check; fix the SAN.
  • Tied to Chain Completeness. If your handshake fails strict verification because of a missing intermediate (chain) rather than SAN mismatch, this sub-weight still fails. See the Chain Completeness fix to confirm which one is actually broken.

What to do next

See how these recommendations apply to your site's current scan results.

Scan domain