Dr.Who

how we build a Domain Audit Report

Version v1 · effective 2026-05-12. This is the canonical specification for every Domain Audit Report delivered while v1 is the current methodology. Each pack carries the methodology version inline; when v2 ships, prior packs continue to point at the v1 page.

1. checks

Each pack runs 15 independent checks: 10 free (mirrored in the public /domain-dossier surface) and 5 paid (Domain Audit Report only). Each check returns one of: ok, timeout, not_applicable, error. Only ok results carry findings.

10 free checks

  • dns-records-lookupare authoritative DNS records published correctly for this domain? (SOC 2 CC6.6 · ISO 27001 A.8.20 · NIST SC-20)
  • mx-lookupwhich mail servers are authoritative for receiving email at this domain? (SOC 2 CC6.7 · ISO 27001 A.8.21 · NIST SC-8)
  • spf-checkerdoes this domain publish an SPF record limiting authorised senders? (SOC 2 CC6.7 · ISO 27001 A.8.20 · NIST SC-8)
  • dmarc-checkerdoes this domain enforce a DMARC policy (quarantine or reject)? (SOC 2 CC6.7 · ISO 27001 A.5.14 · NIST SC-8)
  • dkim-lookupare outgoing emails DKIM-signed under a published selector? (SOC 2 CC6.7 · ISO 27001 A.8.24 · NIST SC-8)
  • tls-certificate-checkeris data in transit protected by a valid, current TLS certificate? (SOC 2 CC6.1 · ISO 27001 A.8.24 · NIST SC-8(1))
  • redirect-checkerdoes the public site redirect HTTP to HTTPS without dropping the user? (SOC 2 CC6.6 · ISO 27001 A.8.23 · NIST SC-7)
  • security-headers-checkerare HSTS, CSP, X-Frame-Options, and related headers configured? (SOC 2 CC6.6 · ISO 27001 A.8.23 · NIST SC-7(8))
  • cors-checkerare cross-origin policies appropriately restrictive at this origin? (SOC 2 CC6.6 · ISO 27001 A.8.23 · NIST AC-4)
  • web-surface-inspectorwhat robots.txt, sitemap, and meta the domain advertises publicly. (SOC 2 CC6.6 · ISO 27001 A.8.9 · NIST CM-7)

5 paid checks

    2. severity grading

    Every ok finding is run through a deterministic rule function that returns one of five severities: info, low, medium, high, critical. Reasons are capped at 120 characters. The rule functions live in the open-source @drwhome/dossier-checks package (MIT) and are versioned alongside this methodology document.

    • info — observational; nothing to act on
    • low — best-practice deviation; defer or batch
    • medium — questionnaire risk; fix in current sprint
    • high — likely audit finding; fix before next assessment
    • critical — active misconfiguration; fix today

    3. subdomain discovery

    Subdomains are sourced exclusively from Certificate Transparency logs (crt.sh) for the apex. We do not brute-force DNS, do not port-scan, and do not actively probe. The cap is 100 subdomains per pack; roots with more CT-discoverable hostnames will see the most-recently-issued 100 selected. DNS, TLS, and header checks are run against each subdomain. Email-auth checks (SPF/DMARC/DKIM/MX) run on the apex only.

    4. retry + inconclusive policy

    Every check has three retries built in. If a check still fails after retries, the pack flags the check as inconclusive rather than presenting a finding, and the order is partially refunded. No silent omissions.

    5. signing scheme

    Each pack ships with a manifest carrying SHA-256 of pack.pdf and pack.json, ISO-8601 UTC scan timestamp, and the signing key id (drwhome-evp-v1 for v1 packs). The manifest is serialized via deterministic canonical-JSON (RFC 8785) and signed with an Ed25519 detached signature.

    Public key: /.well-known/evidence-pack-pubkey.pem · key id: drwhome-evp-v1.

    Attestation rung: (a) third-party signed. Not an RFC 3161 trusted timestamp; not an append-only public log. Both are tracked for v2.

    6. how to verify a pack

    Two equivalent methods. Both run fully offline once the four artifacts and the public key are downloaded.

    Option A — single Node script. Self-contained verifier — Node 20+, no dependencies beyond stdlib:

    # from the directory containing pack.pdf, pack.json, manifest.json, manifest.sig
    curl -O https://drwho.me/scripts/verify-pack.mjs
    curl -O https://drwho.me/.well-known/evidence-pack-pubkey.pem
    node verify-pack.mjs --dir .

    Option B — raw OpenSSL. See /evidence-pack#verify for the OpenSSL-only flow. Requires OpenSSL 3+ (LibreSSL ships with macOS and does not implement pkeyutl -rawin).

    7. version pinning

    Every pack manifest carries signingKeyId identifying which keypair signed it. When v2 ships, v1 packs remain verifiable against the v1 public key (kept indefinitely at /.well-known/evidence-pack-pubkey.pem for current; older keys at /.well-known/evidence-pack-pubkey-v1.pem etc.). The methodology document corresponding to a pack is the page matching the manifest's methodology version.

    8. what we do not do

    • no DNS brute-forcing or wordlist-based subdomain enumeration
    • no port scanning beyond 80/443 (HTTP checks)
    • no exploitation, no fuzzing, no auth-bypass probes
    • no targets on the public-suffix or hosted-provider denylist (lib/dossier/denylist)