← All projects

Web securityP-07

This site, a portfolio with no JavaScript and a strict CSP

How keefe.dev is built and hardened, from a static site with zero JavaScript and a strict CSP to a signed domain and authenticated email, with the scan results to prove it.

LabOngoing4 min read

At a glance

Role
Designer, developer, and administrator
Stack
Astro (static), Cloudflare Pages, Cloudflare DNS
JavaScript
None
Results
A+ Security Headers · A+ Mozilla Observatory · A+ SSL Labs

Executive summary

A security portfolio should practice what it preaches. keefe.dev is a small example of secure-by-default design: a static site with no JavaScript, a strict Content Security Policy, a DNSSEC-signed domain, restrictions on who can issue its certificates, and authenticated email, with no tracking of visitors.

It scores A+ on Security Headers, A+ (145/100) on the Mozilla HTTP Observatory, and A+ on Qualys SSL Labs. Where a score stops short of 100%, the reason is documented below rather than hidden.

Design choices

  • Static output. The site is pre-built HTML and CSS. There is no server-side code, database, login, or admin panel to attack.
  • Zero JavaScript. Even the light/dark theme switch and the mobile menu are pure CSS, so the policy can block scripts entirely. Downloads are plain links with the HTML download attribute.
  • Strict Content Security Policy. default-src 'none', script-src 'none', and styles and fonts only from this site. No unsafe-inline anywhere, so the build is set up to emit no inline styles.
  • Transport security. HSTS with a long max-age, on a .dev domain, which browsers already require to use HTTPS.
  • Other headers. frame-ancestors 'none', nosniff, a strict referrer policy, and a Permissions-Policy that turns off camera, microphone, location, and similar browser features. Files under /downloads/ are always served as attachments.
  • No tracking. No analytics, cookies, or third-party requests. Fonts are self-hosted.
  • Disclosure. A security.txt file (RFC 9116) tells researchers how to report issues.

Hosting and edge configuration

The site deploys to Cloudflare Pages from the main branch. At the edge:

  • Full (strict) TLS, Always Use HTTPS, and TLS 1.3 enabled.
  • Features that rewrite pages are turned off. Email Address Obfuscation and Rocket Loader both work by injecting JavaScript, which the CSP would block, breaking the email link and filling the console with errors. Any feature that would require loosening the policy stays off.

Domain and email

Control What it does Status
DNSSEC Signs the domain’s DNS answers so they can’t be forged Active
CAA Only Let’s Encrypt and Google Trust Services may issue certificates; violations are reported to the security contact Active
SPF Lists the only servers allowed to send mail as the domain Active
DKIM Cryptographically signs outgoing mail (2048-bit key) Active
DMARC Tells receivers to reject mail that fails SPF and DKIM alignment Enforced (p=reject)

DMARC was rolled out in monitor-only mode first, then moved to reject once the reports showed only legitimate mail. Each step was verified by checking that a test message’s headers showed SPF, DKIM, and DMARC all passing.

Verification and results

Scans run on November 11, 2026.

Security Headers report for keefe.dev showing an A+ grade with X-Frame-Options, Strict-Transport-Security, Content-Security-Policy, Permissions-Policy, Referrer-Policy, and X-Content-Type-Options all present. Figure 1. Security Headers: A+, with every recommended header present.

Mozilla HTTP Observatory report for keefe.dev: A+, score 145 out of 100, 12 of 12 tests passed. Figure 2. Mozilla HTTP Observatory: A+, 145/100, 12 of 12 tests passed.

Qualys SSL Labs report for keefe.dev showing A+ on all four Cloudflare edge addresses, two IPv6 and two IPv4. Figure 3. Qualys SSL Labs: A+ on every edge address, over both IPv4 and IPv6.

internet.nl website test for keefe.dev: 95 percent, passing IPv6, DNSSEC, security options, and RPKI, with HTTPS flagged. Figure 4. internet.nl website test: 95%. The one flagged item is explained below.

Verisign Labs DNSSEC analyzer showing an unbroken chain of trust from the root zone, through the .dev zone, to keefe.dev, with every DS record, DNSKEY, and signature check passing. Figure 5. Verisign Labs DNSSEC analyzer: an unbroken chain of trust from the root, through .dev, to keefe.dev. Every signature validates.

Where the scores stop, and why

internet.nl website test (95%). The flagged items (cipher suites, cipher order, and the hash function for key exchange) all concern TLS 1.2 compatibility options that Cloudflare’s edge still offers to very old clients. Modern browsers connect with TLS 1.3 and never use them. Setting the zone’s minimum TLS version to 1.3 should remove them, but testing showed the setting doesn’t reach a Pages custom domain: TLS 1.2 connections still succeeded. Closing the gap would mean re-hosting the site behind a zone route instead of a Pages custom domain. For now I’m accepting 95% with the reason documented.

internet.nl email test. SPF, DKIM, and DMARC all pass. The remaining items, DNSSEC on the mail servers and DANE, depend on the email provider’s infrastructure: Google Workspace’s mail servers aren’t DNSSEC-signed, so no Google Workspace domain can pass them. The practical alternative for inbound mail security is MTA-STS, covered below.

Knowing exactly why a score isn’t 100% is worth more than the number itself.

Key decisions

  • Privacy is part of the design. The site is about the work, not the person, so it holds very little personal information that could be scraped.
  • Avoid features that need exceptions. Each convenience that would require loosening the policy, such as analytics, embedded widgets, or edge script injection, was left out instead.
  • Monitor, then enforce. Email authentication went from monitor-only to enforced only after the reports were clean, the same staged approach I use for production changes.
  • Verify, don’t assume. Every setting was checked from the outside: response headers with curl, protocol support with a TLS 1.2-only connection, and email authentication from the received message’s headers.

What’s next

  • MTA-STS and TLS-RPT so that mail servers sending to this domain must use verified TLS, with daily reports on any failures. Starting in testing mode, then enforced.
  • Revisit TLS 1.2 if re-hosting the site behind a zone route becomes worthwhile.
  • Each November: renew security.txt and re-run these scans.