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.
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
downloadattribute. - Strict Content Security Policy.
default-src 'none',script-src 'none', and styles and fonts only from this site. Nounsafe-inlineanywhere, so the build is set up to emit no inline styles. - Transport security. HSTS with a long max-age, on a
.devdomain, 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.txtfile (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.
Figure 1. Security Headers: A+, with every recommended header present.
Figure 2. Mozilla HTTP Observatory: A+, 145/100, 12 of 12 tests passed.
Figure 3. Qualys SSL Labs: A+ on every edge address, over both IPv4 and IPv6.
Figure 4. internet.nl website test: 95%. The one flagged item is explained below.
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.txtand re-run these scans.