Security posture
How this site defends itself.
This site holds no user data at all — no cookies, no database, no accounts. What does not exist cannot be stolen. On top of that, defenses that actually work are applied in layers.
Threat model (abridged)
- PII_COLLECTED
- 0 bytes
- COOKIES_SET
- 0
- DB_QUERIES
- 0
- TRACKING_PIXELS
- 0
- THIRD_PARTY_SCRIPTS
- 0
- USER_ACCOUNTS
- 0
- SESSION_TOKENS
- 0
- DATA_STORES
- 0
- HEADERS_SERVED
- 28
Data that does not exist cannot be stolen.
Defense in depth (cross-section)
- L1EDGE (VERCEL OR CADDY)requests are first judged here
- L2HTTP HEADERS28 declared, applied per route
- L3CSPenforced on every response
- L4HONEYPOT418 + cookie wipe + incident log
- L5STATIC FILESno server-side code executes
- L6DATAno user data exists to steal
Static files plus minimal server-side compute minimize the attack surface.
HTTP defense headers (verbatim)
Every header below is defined in vercel.json and served on real responses. The same manifest is re-applied by Caddy and the in-app middleware when self-hosted.
/(.*)
- Strict-Transport-Security
- max-age=63072000; includeSubDomains; preload
- X-Content-Type-Options
- nosniff
- X-Frame-Options
- DENY
- Referrer-Policy
- no-referrer
- Cross-Origin-Opener-Policy
- same-origin
- Cross-Origin-Resource-Policy
- same-origin
- Cross-Origin-Embedder-Policy
- credentialless
- Origin-Agent-Cluster
- ?1
- X-Permitted-Cross-Domain-Policies
- none
- X-XSS-Protection
- 0
- X-DNS-Prefetch-Control
- off
- Permissions-Policy
- accelerometer=(), ambient-light-sensor=(), aria-notify=(), autoplay=(), battery=(), bluetooth=(), browsing-topics=(), camera=(), captured-surface-control=(), compute-pressure=(), cross-origin-isolated=(), deferred-fetch=(), deferred-fetch-minimal=(), display-capture=(), document-domain=(), encrypted-media=(), fullscreen=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), identity-credentials-get=(), idle-detection=(), interest-cohort=(), join-ad-interest-group=(), keyboard-map=(), local-fonts=(), magnetometer=(), microphone=(), midi=(), otp-credentials=(), payment=(), picture-in-picture=(), publickey-credentials-create=(), publickey-credentials-get=(), run-ad-auction=(), screen-wake-lock=(), serial=(), shared-storage=(), speaker-selection=(), storage-access=(), synced-reading=(), usb=(), unload=(), web-share=(), window-management=(), xr-spatial-tracking=()
- Reporting-Endpoints
- default="https://harukakaya.dev/api/security-report"
- NEL
- {"report_to":"default","max_age":604800,"include_subdomains":true,"success_fraction":0,"failure_fraction":1}
- X-Security-Contact
- https://harukakaya.dev/.well-known/security.txt
/((?!keystatic|api/keystatic).*)
- Content-Security-Policy
- default-src 'self'; script-src 'self'; style-src 'self' https://fonts.googleapis.com; style-src-attr 'unsafe-inline'; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; media-src 'self'; worker-src 'self'; manifest-src 'self'; frame-src 'none'; child-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'; block-all-mixed-content; upgrade-insecure-requests; report-uri /api/security-report; report-to default
/keystatic/:path*
- X-Robots-Tag
- noindex, nofollow
- Cache-Control
- no-store
- Content-Security-Policy
- default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://avatars.githubusercontent.com https://raw.githubusercontent.com; font-src 'self' data:; connect-src 'self' https://api.github.com https://raw.githubusercontent.com; worker-src 'self' blob:; frame-ancestors 'none'; base-uri 'self'; form-action 'self' https://github.com; object-src 'none'; upgrade-insecure-requests
/api/keystatic/:path*
- X-Robots-Tag
- noindex, nofollow
- Cache-Control
- no-store
- Content-Security-Policy
- default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'self' https://github.com
/api/security-report
- Cache-Control
- no-store
- Access-Control-Allow-Origin
- *
- Access-Control-Allow-Methods
- POST, OPTIONS
- Access-Control-Allow-Headers
- Content-Type
/.well-known/security.txt
- Content-Type
- text/plain; charset=utf-8
- Cache-Control
- public, max-age=86400
Honeypot
Paths scanners target (/.env, /wp-admin, anything .php) all answer HTTP 418 and request a site-data wipe via Clear-Site-Data. Every probe is assigned a deterministic incident ID and logged server-side. Clients declaring offensive tooling in the User-Agent are denied on every path.
Verify it:
$ curl -sI https://harukakaya.dev/.env HTTP/2 418 x-incident-id: KY-24A62BB9 clear-site-data: "cookies", "storage"
Found a vulnerability?
Report it via the contacts in security.txt. On a static site the issue most likely lives in the hosting platform or Astro itself — but I will look into anything you send.
Hall of fame
Researchers who found a vulnerability here and earned a place on this list: