Static sites have a reputation for being inherently secure. No server-side code means no SQL injection, no remote code execution, no session hijacking. But "more secure than a dynamic app" is not the same as "secure." Static sites still face real threats: man-in-the-middle attacks, script injection through CDN compromises, clickjacking, and data leakage through mixed content.
The good news is that the fixes are straightforward and free. Here is a practical checklist for locking down a static site.
HTTPS: The Non-Negotiable Baseline
Every static site should be served over HTTPS. This is not optional in 2026. Browsers flag HTTP sites as "Not Secure," search engines penalize them, and modern APIs like the Clipboard API, Geolocation, and Service Workers refuse to work without a secure context.
If you are using a static hosting provider (GitHub Pages, Cloudflare Pages, Netlify, Vercel), HTTPS is automatic and free via Let's Encrypt. If you are self-hosting on a VPS, Certbot with Let's Encrypt takes about five minutes to set up.
The common pitfall is mixed content: your page loads over HTTPS but includes resources (scripts, stylesheets, images) over HTTP. Browsers block mixed active content (scripts, iframes) entirely and may warn about mixed passive content (images). The fix is simple -- use https:// URLs everywhere, or use protocol-relative URLs (//example.com/script.js), or better yet, self-host critical resources.
Add an HTTPS redirect to catch any HTTP requests:
// Client-side redirect (for static sites without server config)
if (location.protocol !== "https:" &&
location.hostname !== "localhost" &&
location.hostname !== "127.0.0.1") {
location.replace("https:" +
location.href.substring(location.protocol.length));
}
Content Security Policy
Content Security Policy (CSP) is an HTTP header that tells the browser which sources of content are allowed on your page. It is the single most effective defense against cross-site scripting (XSS) attacks. Even on a static site, XSS is possible if you load third-party scripts (ads, analytics, CDN libraries) that get compromised.
A CSP header for a typical static site that loads Bootstrap from a CDN and uses Google Fonts might look like this:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://code.jquery.com
https://cdn.jsdelivr.net
https://stackpath.bootstrapcdn.com;
style-src 'self' 'unsafe-inline'
https://stackpath.bootstrapcdn.com
https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data:;
connect-src 'self';
The key directives:
default-src 'self'-- block everything not explicitly allowedscript-src-- whitelist exactly which domains can serve JavaScriptstyle-src-- allow styles from specific sources ('unsafe-inline'is often needed for inline styles but weakens CSP)connect-src-- restrict wherefetch()andXMLHttpRequestcan connect
If your static host does not support custom headers, you can use a <meta> tag as a fallback (though it is less powerful -- it cannot set frame-ancestors or report-uri):
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' https://code.jquery.com">
Subresource Integrity
When you load a script or stylesheet from a CDN, you are trusting that CDN to serve unmodified files. Subresource Integrity (SRI) lets you verify that the file has not been tampered with by including a cryptographic hash of the expected content:
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYn
UhczAWQ7yMGqVTTe6OFp3gMa"
crossorigin="anonymous"></script>
If the file served by the CDN does not match the hash, the browser refuses to execute it. This protects you from CDN compromises, which are rare but have happened in the wild (the Polyfill.io incident in 2024 is a recent example).
Generate SRI hashes with: shasum -b -a 384 file.js | xxd -r -p | base64 or use srihash.org.
Other Quick Wins
X-Frame-Options (or frame-ancestors in CSP) prevents your site from being embedded in an iframe on another domain, blocking clickjacking attacks.
X-Content-Type-Options: nosniff prevents browsers from MIME-sniffing a response away from the declared content type. This stops attacks where a browser interprets a non-JavaScript file as script.
Referrer-Policy: strict-origin-when-cross-origin limits how much URL information is leaked when users click links to external sites. The full URL (including query parameters) stays private for cross-origin requests.
Permissions-Policy (formerly Feature-Policy) lets you disable browser features your site does not use -- camera, microphone, geolocation, payment. Less attack surface, even if it seems unlikely someone would exploit these on a static site.
Testing Your Security Headers
Use securityheaders.com to scan your site and get a grade. Most static sites score D or F out of the box because they ship with zero security headers. Adding the headers described above typically gets you to an A.
Static sites are simple, but simple does not mean you can skip security basics. HTTPS, CSP, and SRI are free, take minimal effort to set up, and protect both you and your users from real-world attacks. There is no good reason not to implement them.