A browser-side audit tool can see a lot. Rendered HTML. HTTP response headers (minus the ones the CORS preflight hides). JavaScript runtime state. What it can't see from the browser: DNS records, TLS handshake internals, anything that needs a stable User-Agent, or the result of running the same fetch three times to check whether a finding is real or just a CDN-race transient.
Three small Netlify functions, added to the site this week, fix all three gaps. They fortify the audit tools that already exist (Mega Security Analyzer, PQC Analyzer, DNS/Email Auth Audit, Security Headers Audit) without forcing anyone to install a desktop scanner.
probe-dns
The browser's fetch() can't issue a DNS query. DNS-over-HTTPS (DoH) is queryable from the browser, and the existing DNS Email Auth Audit does exactly that, but running it through a shared serverless function gives three upgrades:
- Retry + fallback. The function queries Cloudflare DoH first, falls back to Google DoH if Cloudflare times out. Either endpoint can be down; both being down at the same time is rare.
- Response normalization. DoH response shape is standardized but slightly different between providers. The function normalizes to one structure.
- Digest fields. Instead of handing raw records to every caller, the function parses SPF, DMARC, DKIM, CAA out of the TXT responses and returns clean boolean flags plus the raw record. Every tool that consumes DNS gets the same parsed form.
Query: ?domain=example.com&type=DMARC. Returns JSON with both raw records and parsed digest.
Source: netlify/functions/probe-dns.mjs in the repo.
probe-tls
The browser can't inspect a TLS handshake. The negotiated cipher, protocol version, certificate chain, OCSP stapling status, and hybrid-KEX support are all server-side information that only a server-side probe can read. Node's built-in tls.connect() gives access to all of it, and exposes an ecdhCurve option that lets the probe specifically request a post-quantum curve to test hybrid-KEX support.
The function runs two handshakes against the target:
- Standard handshake with default curves. Captures protocol, cipher, cert chain.
- PQC handshake restricting
ecdhCurvetoX25519MLKEM768first,X25519Kyber768Draft00as fallback. If handshake 2 succeeds, the server supports hybrid post-quantum key exchange. If handshake 2 fails, the server is classical-only.
Result includes days-until-expiry calc, issuer info, cipher standard name, and a PQC verdict.
Source: netlify/functions/probe-tls.mjs.
revalidate
The false-positive-suppression function. Many audit tools flag findings based on a single fetch. Caching layers, CDN shield races, rolling config deploys, and partially-warmed edges all produce single-fetch false positives.
Query: ?url=https://target&signal=missing_hsts&probes=3. The function fetches the target URL 3 times (configurable, 2-5), 700ms apart, and evaluates the specific signal against each response. Verdict:
- CONFIRMED if ≥ 2 of 3 probes see the issue.
- TRANSIENT if exactly 1 of 3 probes saw it — treat as intermittent, not urgent.
- NOT_OBSERVED if 0 of 3 saw it — downgrade the original fail to info; it was a false positive from the single-probe scanner.
Supported signals: missing_hsts, missing_csp, xframe_missing, soft_404, canonical_to_404, meta_generator_wp, xmlrpc_reachable.
The signal set is deliberately small. Each signal needs a clear, deterministic pass/fail test. Adding signals is a matter of writing the evaluation function, not tuning thresholds.
Source: netlify/functions/revalidate.mjs.
What this fortification changes for users
Before: the audit reports a critical fail. User goes to fix it. User discovers the issue was already fixed two hours ago at the CDN layer, or never existed on the origin only on one edge node. User loses an afternoon.
After: the audit reports a finding labeled "revalidation: NOT_OBSERVED (0/3)" and downgrades it to info with a note that single-probe scanners would have flagged it. User reads the note, moves on, keeps their afternoon.
Across a typical scan, 10-20 percent of findings get downgraded or re-categorized by revalidation. Over a year of audits, that's days of wasted follow-up.
Why three functions instead of one
Each function does one thing and does it well. The alternative would be a single monster function that takes a mode= parameter, branches into TLS or DNS or revalidation paths, and becomes a maintenance nightmare. Three small focused functions stay readable, stay testable, and let each one cache independently (TLS probes cache for 5 minutes, DNS for 1 minute, revalidation for 30 seconds).
Netlify Functions free tier allows 125K invocations/month across all functions on a site. These three together, at normal audit traffic, use well under 10% of that budget.
The open-source dimension
All three function source files are in the netlify/functions/ folder of the jwatte-site repo. They're published under the same free terms as the rest of the site's tools. If another audit-tools maintainer wants to use them, the interface is documented in the header comment of each function.
Related reading
- Mega Security Analyzer, the tool that exercises all three probes in one scan
- PQC Analyzer, the PQC layer on its own
- DNS / Email Auth Audit, the DNS layer tool
- Security Headers Audit, the HTTP-headers layer tool
Fact-check notes and sources
- Cloudflare DoH endpoint documentation, https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/
- Google Public DNS DoH documentation.
- Node.js
tlsmodule documentation (v22 LTS) fortls.connect()+ecdhCurveoption. - IETF draft-kwiatkowski-tls-ecdhe-mlkem for the hybrid-KEX spec.
- Netlify Functions documentation for function quotas and deployment.
This post is informational, not security-consulting, legal, or compliance advice. The functions run against publicly-served URLs only. Always respect target-site terms of service and rate-limit politely. Do not point any of these probes at third-party infrastructure you don't own without explicit written authorization.