Colophon
How this siteis secured
What the browser is allowed to load here, and how a message leaves the page. This is a description of the headers in this repository, not a certification.
01
Content Security Policy
Every response carries a Content-Security-Policy. The directives below are the ones this site sends.
- default-src 'self'. Resources come from this origin unless a later rule names another.
- script-src 'self' 'unsafe-inline' and Google Tag Manager. Scripts are first-party. Inline scripts stay allowed because Next.js boots the page that way. The Tag Manager host is listed so analytics can be switched on. It is not loaded unless that switch is set.
- style-src 'self' 'unsafe-inline'. Styles are first-party, including the inline styles Next.js emits.
- img-src 'self', data, blob, and the Google Analytics image hosts. Photographs are files on this site.
- font-src 'self' and data. Fonts are self-hosted at build time. The page does not call a font CDN.
- connect-src 'self' and the Google Analytics endpoints. The page does not open other network connections unless analytics is enabled.
- form-action 'self'. This directive only governs where the visitor's browser may submit forms. The contact form posts to /api/contact on this origin. The server-side relay through FormSubmit is separate.
- base-uri 'self'. The document base cannot be retargeted.
- object-src 'none'. No plugins and no embedded objects.
- frame-ancestors 'none'. Other sites cannot frame this one.
default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://www.google-analytics.com https://www.googletagmanager.com; font-src 'self' data:; connect-src 'self' https://www.google-analytics.com https://*.google-analytics.com https://*.analytics.google.com https://www.googletagmanager.com; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'
02
Other response headers
- X-Content-Type-Options. nosniff
- Referrer-Policy. strict-origin-when-cross-origin
- X-Frame-Options. DENY
- Permissions-Policy. camera=(), microphone=(), geolocation=(), payment=(), usb=()
nosniff stops the browser from guessing a file type. The referrer policy sends only the origin across sites. Framing is denied a second time with X-Frame-Options. Camera, microphone, location, payment, and USB are turned off.
03
Scripts and trackers
No third-party runtime script is included by default. There is no advertising tag, no tag manager on the page, and no script loaded from a CDN.
Google Analytics is rendered only when the environment variable NEXT_PUBLIC_GA_ID is set. With that variable unset, the analytics component is not in the page, and no tracker runs.
The home, about, and contact portraits are photographs on this site. The image optimizer serves them as AVIF or WebP at the size the screen needs. A line drawing in SVG sits around each photograph. The drawing does not replace or retouch the photograph. With reduced motion, the lines stay still.
The threat graph below is the same kind of drawing: grey lines and one accent. It is not a feed, and it does not describe traffic on this site. With reduced motion, it stays still.
Drawing
Threat graph
Nodes and edges only. One signal brightens. Nothing here is a live monitor.
04
The contact form
The form posts to /api/contact on this origin. form-action only governs where the visitor's browser may submit forms. The server-side relay through FormSubmit is separate: the server requires a name, an email, and a message, then forwards the note to FormSubmit, which delivers it to an address kept in the server environment. A hidden honeypot field is discarded.
That address is never rendered. There is no mailto link and no published email address. The browser is sent back to the contact page with a success or error flag. Messages are not stored in a database on this site.
05
What this pagedoes not claim
These are the headers and the form path this repository sets. They are not a penetration test, a seal, or a promise about email delivery. HTTPS is provided by the host in front of the site.