Web TLS grading
This page covers web TLS grading (
src/grade.ts). Mail endpoints and mail DNS are graded separately bysrc/grade-mail.tsandsrc/grade-mail-dns.ts, and pasted configuration bysrc/config/analyze.ts— see mail-and-config.md for those rules and why they deliberately differ (no HSTS on port 993; a hostname mismatch warns rather than caps).
Each scan produces a numeric score (0–100) and a letter grade (A+→F), plus a list of
concrete fixes. The logic lives in src/grade.ts and is fully unit-tested —
this page documents it.
Inputs
Section titled “Inputs”The native provider probes the endpoint directly (Node tls/https) for:
- Protocol support — TLS 1.0, 1.1, 1.2, 1.3 (each tested individually).
- Negotiated ciphers — classified weak / ok / strong. With opt-in cipher enumeration
(
--ciphers), every accepted TLS ≤1.2 suite is walked, so a weak suite the server accepts as a fallback (not just its preferred one) also trips the weak-cipher penalty. - Certificate — validity dates, days-until-expiry, chain trust, self-signed.
- HSTS — presence,
max-age,includeSubDomains,preload.
The host is resolved to all its A/AAAA addresses and each IP is probed independently. The
inputs above are aggregated to the worst case across reachable addresses (a protocol counts as
enabled if any address offers it; a weak cipher on any address counts), so a single grade reflects
the weakest reachable IP. The certificate and HSTS are read from the primary (first reachable)
address. Per-address detail is returned under addresses in the JSON output.
SSL Labs can optionally enrich the result with its own grade (stored under externalGrades); it
does not change the computed score. SSLv2/SSLv3 cannot be probed from modern OpenSSL, so they are
reported as not-detected (SSL Labs will flag them if present).
Scoring model
Section titled “Scoring model”Start at 100, subtract penalties, then apply hard caps:
| Finding | Effect |
|---|---|
| SSLv2 or SSLv3 enabled | grade F (score ≤ 20) |
| Certificate expired | grade F (score ≤ 20) |
| Self-signed certificate | score capped at 40 |
| Untrusted chain | score capped at 50 |
| Certificate hostname mismatch | score capped at 50 |
| RSA key < 2048 bits | −20 (< 1024 bits also caps at 40) |
| No forward secrecy | −10 |
| TLS 1.0 enabled | −25 |
| TLS 1.1 enabled | −15 |
| TLS 1.2 not available | −20 |
| TLS 1.3 not available | −5 |
| Weak cipher offered | −20 |
| HSTS missing | −10 |
HSTS max-age < 6 months |
−3 |
| Cert expires < 14 days | −15 |
| Cert expires < 30 days | −5 |
Score → grade
Section titled “Score → grade”| Score | Grade |
|---|---|
| 95–100 | A+ |
| 80–94 | A |
| 65–79 | B |
| 50–64 | C |
| 35–49 | D |
| 0–34 | F |
Every penalty also attaches a fix (id, severity, title, detail) shown on the domain detail page.