Methodology

How the security rating is computed

Version 1, in force since 15 October 2026. Every rule that moves a score is on this page, and the tables are rendered from the same definitions the scoring engine runs.

The scale

  1. F0–200
  2. D201–400
  3. C401–600
  4. B601–800
  5. A801–950
A domain starts at 950; each failed check subtracts its tier cost; the floor is 0.

A security rating is the result of applying a published rule set to evidence gathered by passive observation: the public DNS records of a domain, the registrar’s public record, one TLS handshake per protocol version with its web servers, one request for the landing page over HTTP and over HTTPS, and public data sources — Shodan’s InternetDB for open ports and known vulnerabilities, certificate-transparency logs, DNS blocklists.

Nothing is probed beyond the landing page, no port is scanned by us, and nothing is sent to the observed system that a browser or a mail server would not send. The rules below are the whole method: every point a score loses is listed here with its cost, and a change to the rules is a new version, dated, that never rewrites an earlier score.

  • A domain starts at 950 and loses points for each failed check. The floor is 0.
  • Every check has a tier — critical, high, medium, low or informational — with a fixed cost. Informational checks are shown and never cost anything.
  • The overall score is computed on every failed check, with no cap per category. Category scores are shown for orientation and do not feed the overall score; a domain with many problems loses the full amount for each.
  • An entity with several hosts or domains is pulled toward its worst asset: the score is the average, pulled halfway toward the minimum, so a bad host cannot hide behind good ones.
  • A score always comes with its coverage: how many checks were evaluated, how many this version does not cover, and how many could not be observed. A score with twenty checks not observed is a weaker claim than one with two, and the page that shows it says so.

Statuses

Every check of every observation ends in one of these, and the coverage line under a score counts them.

StatusMeaningEffect on the score
passobserved, rule satisfiednone
failobserved, rule violated; evidence attachedminus the tier cost
infoobserved, informationalnone; shown
not coveredthis version does not implement the checknone; counted in coverage
not observedcould not be observed inside the allowed means: no public-source data, host unresolvable, a source refusednone; counted in coverage, shown as a gap
not applicablethe check’s premise is absent — the HSTS details of a host with no HTTPS, the SPF qualifier of a domain with no SPF recordnone; counted in coverage, not a gap
errorour observer failed: a timeout, our bugnone; the observation is marked partial

Provisional checks are evaluated and shown with their tier but cost nothing, for at least one method version, so that a reader sees them before they move the number.

Why these costs

No rating vendor publishes per-check costs, and a regression over 396 public reports of one of them recovers only half the variance, so there was nothing to copy. These tiers are decided, not measured, and the reasoning for the most expensive ones is written down so that an auditor can argue with it. What the regression does support is the ordering: a missing DMARC record, no HTTPS, legacy TLS, untrusted certificates and end-of-life software sit at the top; single headers, cookie flags and open standard ports at the bottom.

CheckTierWhy
ENC-1HTTPS is availablecriticalNo transport security at all; every other TLS check is moot. The single largest cost in the regression.
ENC-2Certificate chain is trustedcriticalAn untrusted chain is indistinguishable from an interception; browsers warn and users click through.
ENC-4Certificate not expiredcriticalBrowsers block the page; the site is effectively down for careful users and open for careless ones.
EML-3SPF does not end in +allcriticalAuthorises every sender on the internet to mail as the domain.
REP-1Domain not listed on Spamhaus DBL or SURBLcriticalAn active abuse signal, not a configuration gap.
REP-3Not flagged by Google Safe BrowsingcriticalThe domain is currently serving something malicious.
NET-3No database port exposed (1433, 1521, 3306, 5432, 6379, 9200, 27017, 11211)criticalDirect exposure of data; the port class most correlated with breach in the public vendor methodologies.
NET-2No telnet (23) exposedcriticalClear-text credentials on a management channel.
VUL-2Server software not end-of-lifecriticalNo security fixes will ever arrive; the second-largest cost in the regression.
EML-7DMARC record presenthighThe regression’s largest email cost; high rather than critical because SPF may still exist.

Every other tier assignment follows the same two questions: what can an attacker do with it today, and does the regression over real domains agree with the ordering.

Not in this version

Dark-web and credential-leak monitoring, brand protection (typosquats, fake apps), questionnaires beyond the seven-item attestation below, operational risk as a category, cipher-suite enumeration beyond one weak-list handshake, per-vulnerability severity weighting. Each is listed as not covered where it would appear, and counted in the coverage of every score.

Where the observation comes from

Observation runs from our own worker, hosted in the European Union (Amsterdam), on a shared outbound address. For one domain it makes the DNS lookups listed above, one registrar lookup, at most six TLS handshakes per web host, two requests for the landing page, and the public-source queries — once a day at most, and never more than five hosts per domain.

What is observed is kept with the score as evidence: the record, the certificate dates, the header values. Response bodies are not kept.

Opting out

A domain owner who does not want their public posture observed by this product can ask for the domain to be excluded. Write to hello@tacans.com naming the domain. The request is honoured, and the domain is shown as “not observed at the owner’s request” to every customer who registered it.

The rules

Method version 1. Every domain starts at 950; each failed check subtracts its tier cost; the floor is 0.

TierCost
critical100
high50
medium20
low6
info0

Roll-up

domain_loss  = Σ domain-level costs + 0.5 × max(host_loss) + 0.5 × mean(host_loss)
domain_score = max(0, 950 − domain_loss)
entity_score = 0.5 × min(domain_score) + 0.5 × mean(domain_score)

Worst case per category, counting each mutually exclusive group once. Informational: the overall score has no per-category cap.

CategoryChecksCoveredWorst-case loss
Email1212302
DNS99134
Encryption1919728
Website1616226
Network66306
Vulnerability Management32150
Attack Surface44100
IP/Domain Reputation33250
Data Leakage2120
Operational Risk000

Email12 checks

IdCheckLevelTierCostSourceRemediation
EML-1SPF record presentdomainhigh50DNS TXTPublish an SPF record naming the senders allowed for this domain.
EML-2SPF syntax valid (one record, ≤ 10 lookups)domainmedium20DNS TXTKeep one SPF record and at most ten DNS lookups; receivers ignore a broken record.
EML-3SPF does not end in +alldomaincritical100DNS TXTReplace `+all` — it authorises every sender on the internet to mail as this domain.
EML-4SPF does not end in ?alldomainhigh50DNS TXTReplace `?all` with `-all` (or `~all` while DMARC is being rolled out).
EML-5SPF ends in -all rather than ~alldomainlow6DNS TXTMove to `-all` once DMARC reporting shows no legitimate sender is missing.
EML-6SPF has no ptr mechanismdomainlow6DNS TXTRemove `ptr`; it is deprecated and slow, and some receivers ignore records that use it.
EML-7DMARC record presentdomainhigh50DNS TXT _dmarcPublish `_dmarc` with at least `p=none` and a reporting address, then tighten.
EML-8DMARC policy is not p=nonedomainhigh50DNS TXT _dmarcMove the policy to `p=quarantine`, then `p=reject`; `p=none` protects nobody.
EML-9DMARC policy is p=rejectdomainlow6DNS TXT _dmarcMove from `p=quarantine` to `p=reject` once reports are clean.
EML-10DMARC pct is 100domainlow6DNS TXT _dmarcRemove `pct` or set it to 100; a partial policy leaves a share of mail unprotected.
EML-11DMARC has a reporting address (rua)domaininfo0DNS TXT _dmarcAdd `rua=` so spoofing attempts are reported to you.
EML-12Every MX host resolvesdomainmedium20DNS MX + A/AAAARemove or fix MX records that point at hosts that no longer exist.

DNS9 checks

IdCheckLevelTierCostSourceRemediation
DNS-1DNSSEC enableddomainlow6DNS DNSKEY/DSSign the zone and publish the DS record at the registrar.
DNS-2CAA record presentdomainlow6DNS CAAPublish a CAA record naming the certificate authorities allowed to issue for this domain.
DNS-3Registrar transfer lock setdomainmedium20RDAP statusEnable `clientTransferProhibited` at the registrar.
DNS-4Registrar delete lock setdomainlow6RDAP statusEnable `clientDeleteProhibited` at the registrar.
DNS-5Registrar update lock setdomainlow6RDAP statusEnable `clientUpdateProhibited` at the registrar.
DNS-6Domain does not expire within 30 daysdomainhigh50RDAP expiryRenew the domain now and enable auto-renewal.
DNS-7Domain does not expire within 90 daysdomainlow6RDAP expiryRenew the domain or confirm auto-renewal is on.
DNS-8Every NS host resolvesdomainmedium20DNS NS + A/AAAARemove or fix nameserver records that point at hosts that do not resolve.
DNS-9Domain not on a registry or registrar holddomainmedium20RDAP statusResolve the hold with the registrar; a held domain can stop resolving without notice.

Encryption19 checks

IdCheckLevelTierCostSourceRemediation
ENC-1HTTPS is availablehostcritical100TLS handshakeServe the site over HTTPS with a certificate from a trusted authority.
ENC-2Certificate chain is trustedhostcritical100TLS handshakeInstall the full chain from a publicly trusted authority; a self-signed or orphaned certificate is indistinguishable from an interception.
ENC-3Hostname matches the certificatehosthigh50TLS handshakeIssue a certificate whose names include this host (or a matching wildcard).
ENC-4Certificate not expiredhostcritical100TLS handshakeRenew the certificate and automate renewal.
ENC-5Certificate not expiring within 20 dayshostmedium20TLS handshakeRenew before expiry; automate renewal so this never recurs.
ENC-6Certificate validity ≤ 398 dayshostlow6TLS handshakeIssue certificates for at most 398 days; browsers distrust longer ones.
ENC-7Key strength ≥ RSA 2048 / EC 256hosthigh50TLS handshakeRe-issue with an RSA ≥ 2048-bit or EC ≥ 256-bit key.
ENC-8Signature algorithm not SHA-1 or MD5hosthigh50TLS handshakeRe-issue with a SHA-256 (or stronger) signature.
ENC-9TLS 1.0 not offeredhostmedium20TLS handshake per protocolDisable TLS 1.0 on the server.
ENC-10TLS 1.1 not offeredhostlow6TLS handshake per protocolDisable TLS 1.1 on the server.
ENC-11SSL 2 / SSL 3 not offeredhosthigh50TLS handshake per protocolDisable SSLv2 and SSLv3; both are broken.
ENC-12TLS 1.2 or 1.3 offeredhosthigh50TLS handshake per protocolEnable TLS 1.2 and 1.3; modern clients refuse anything older.
ENC-13HTTP redirects to HTTPShosthigh50GET / over HTTPRedirect every HTTP request to HTTPS with a 301.
ENC-14HTTPS does not redirect to HTTPhosthigh50GET / over HTTPSNever downgrade a secure request; fix the redirect target.
ENC-15HSTS header presenthostmedium20GET / over HTTPSSend `Strict-Transport-Security` on every HTTPS response.
ENC-16HSTS max-age ≥ 6 monthshostlow6GET / over HTTPSSet `max-age` to at least 15552000 seconds.
ENC-17HSTS includes subdomainshostlow6GET / over HTTPSAdd `includeSubDomains` once every subdomain serves HTTPS.
ENC-18Domain on the HSTS preload listhostinfo0HSTS preload status (public)Submit the domain at hstspreload.org once HSTS is enforced with preload.
ENC-19No known-weak cipher accepted (RC4, 3DES, NULL, EXPORT)hostmedium20TLS handshake with a weak-cipher listRemove RC4, 3DES, NULL and EXPORT suites from the server configuration.

Website16 checks

IdCheckLevelTierCostSourceRemediation
WEB-1Content-Security-Policy presenthostmedium20Response headersSend a Content-Security-Policy; start with `default-src 'self'` and widen deliberately.
WEB-2CSP has no unsafe-inline in script-src without a nonce or hashhostmedium20Response headersReplace inline scripts with nonces or hashes.
WEB-3CSP has no unsafe-evalhostlow6Response headersRemove `unsafe-eval`; refactor code that needs `eval`.
WEB-4Clickjacking protection (X-Frame-Options or frame-ancestors)hostmedium20Response headersSend `X-Frame-Options: DENY` or a CSP `frame-ancestors` directive.
WEB-5X-Content-Type-Options: nosniffhostlow6Response headersSend `X-Content-Type-Options: nosniff`.
WEB-6Referrer-Policy is not unsafe-urlhostlow6Response headersSend `Referrer-Policy: strict-origin-when-cross-origin` or stricter.
WEB-7Server header carries no versionhostlow6Response headersRemove the version from the `Server` header.
WEB-8X-Powered-By absenthostlow6Response headersRemove the `X-Powered-By` header.
WEB-9X-AspNet-Version / X-AspNetMvc-Version absenthostmedium20Response headersDisable version headers in the ASP.NET configuration.
WEB-10Session cookies have Securehosthigh50Set-Cookie on /Set the `Secure` attribute on every session cookie.
WEB-11Session cookies have HttpOnlyhostmedium20Set-Cookie on /Set `HttpOnly` on session cookies so scripts cannot read them.
WEB-12Cookies declare SameSitehostlow6Set-Cookie on /Set `SameSite=Lax` or `Strict` on every cookie.
WEB-13Landing page responds 2xx or 3xxhostlow6GET / over HTTPSServe a real page at `/`; an error page is an unmaintained surface.
WEB-14No mixed content on the landing pagehostmedium20HTML of /Load every subresource over HTTPS, or send `upgrade-insecure-requests`.
WEB-15Permissions-Policy presenthostinfo0Response headersSend a `Permissions-Policy` that disables features the site does not use.
WEB-16CORS does not allow * with credentialshostmedium20Response headersNever combine `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`.

Network6 checks

IdCheckLevelTierCostSourceRemediation
NET-1No remote-management port exposed (22, 3389, 5900, 5985/5986)hosthigh50Shodan InternetDBPut remote management behind a VPN or an allowlist; close it on the public interface.
NET-2No telnet (23) exposedhostcritical100Shodan InternetDBDisable telnet; it sends credentials in clear text.
NET-3No database port exposed (1433, 1521, 3306, 5432, 6379, 9200, 27017, 11211)hostcritical100Shodan InternetDBBind databases to private interfaces; reach them through the application or a VPN.
NET-4No file-sharing port exposed (21, 445, 2049)hosthigh50Shodan InternetDBClose FTP, SMB and NFS on the public interface; use SFTP behind authentication if needed.
NET-5No plaintext mail-retrieval port (110, 143) on a web hosthostlow6Shodan InternetDBServe mail retrieval over TLS (995, 993) and from a mail host, not the web host.
NET-6Open ports beyond 80 and 443 listedhostinfo0Shodan InternetDBReview every listed port; close what the host does not need.

Vulnerability Management3 checks

IdCheckLevelTierCostSourceRemediation
VUL-1No known CVEs reported on the exposed serviceshosthigh50Shodan InternetDB vulnsPatch or upgrade the affected service; re-observe to confirm.
VUL-2Server software not end-of-lifehostcritical100Response headers + endoflife.dateUpgrade to a supported release; end-of-life software receives no security fixes.
VUL-3No known-vulnerable JavaScript libraries on the landing pagehosthigh (not covered)0HTML of / (retire.js rules)Upgrade the library to a release without known vulnerabilities.

Attack Surface4 checks

IdCheckLevelTierCostSourceRemediation
ASF-1No dangling subdomain (CNAME to an unclaimed service)domainhigh50CT search + DNS CNAMERemove DNS records that point at services you no longer own; they can be claimed by anyone.
ASF-2No admin interface exposed on an observed hosthosthigh50Shodan InternetDB tagsPut administrative interfaces behind a VPN or an allowlist.
ASF-3Subdomains observed in certificate-transparency logsdomaininfo0CT searchReview the list; decommission what is not meant to exist.
ASF-4Wildcard DNS presentdomaininfo0DNSPrefer explicit records; a wildcard answers for names you never created.

IP/Domain Reputation3 checks

IdCheckLevelTierCostSourceRemediation
REP-1Domain not listed on Spamhaus DBL or SURBLdomaincritical100DNSBLFind and stop the abuse, then request delisting.
REP-2Resolved IPs not listed on Spamhaus ZENhosthigh50DNSBLClean the host and request delisting; a shared IP may need a move.
REP-3Not flagged by Google Safe Browsingdomaincritical100Safe Browsing API (optional key)Remove the malicious content and request a review in Search Console.

Data Leakage2 checks

IdCheckLevelTierCostSourceRemediation
LEK-1Landing page is not a directory listinghostmedium20HTML of /Disable directory listing on the web server.
LEK-2No credential-shaped strings in landing-page HTML or JavaScripthosthigh (not covered)0HTML of /Rotate the exposed credential and move it out of client-side code.

Operational Risknot covered in this version

Attestation (version 1) and the blend

Observation measures what the public internet sees. An attestation records what a person at the customer has been shown about a supplier — certificates on file, clauses in the contract, a named contact, a recent test — answered item by item from the evidence, not from expectation, and recorded under that person’s name with the date.

An attested supplier carries a third number beside the two: the blend, half observation and half attestation, labelled as blended wherever it appears. Items answered as not applicable leave the denominator, so a supplier that never touches card data is not marked down for having no PCI attestation; an unanswered attestation is an absence, never a zero. The observation score and its history are untouched by any attestation.

IdItemWhat counts as seenPoints
ATT-1ISO/IEC 27001 certificate on fileA current certificate from an accredited body, with its scope statement covering the service you buy.200
ATT-2SOC 2 Type II report on fileA report dated within the last twelve months, read for exceptions.200
ATT-3PCI DSS attestation on fileAn AOC or SAQ dated within the last twelve months; not applicable where the supplier never touches card data.100
ATT-4A named security contactA person or a monitored mailbox you have reached at least once.50
ATT-5Incident notification clause in the contractThe contract names a deadline for telling you about a breach that touches your data.150
ATT-6Data processing agreement in placeSigned, naming the processing and the sub-processors; not applicable where no personal data is processed.100
ATT-7Independent penetration test in the last twelve monthsA report or an attestation letter from the tester, with the scope.150
attestation_score = 950 × Σ points(yes) / Σ points(applicable)   (null when nothing applicable is answered)
blended_score     = 0.5 × observation_score + 0.5 × attestation_score   (only when both exist)

Version history

A change to any rule is a new version. A score keeps the version it was computed with, and history is never rescored.

VersionDateChange
12026-10-15First published method.