Web security case study

Hardening the site you’re reading.

The goal was not to claim that a static site is invulnerable. It was to reduce its attack surface, prevent accidental publication, and make risky code patterns easier to catch before deployment.

The starting risk

The source directory contained public pages alongside project notes, infrastructure documentation, build files, and draft content. Publishing the whole directory would expose material that visitors never needed. Inline scripts and broad browser permissions would also make a future injection bug more damaging.

The controls

  • An allowlisted build copies only approved public files into a separate dist directory.
  • A strict Content Security Policy limits scripts to the site itself, blocks inline scripts and style attributes, and denies plugins, framing, and unexpected form destinations.
  • Additional response headers control MIME sniffing, referrers, browser capabilities, framing, and cross-origin isolation behavior.
  • JavaScript updates use DOM APIs and textContent instead of HTML injection sinks.
  • Automated checks flag inline handlers, dynamic code execution, missing local assets, unsafe external-tab links, path escapes, and private files in the production bundle.

Directory traversal boundary

A static host does not provide an application-level file-read endpoint, so there is no legitimate URL parameter that maps to a server path. The production allowlist strengthens that boundary: private source files are not present in the published artifact in the first place.

Verification

The release workflow compiles CSS, rebuilds the production directory from the allowlist, runs the security scanner, and checks dependencies. The public deployment is then verified for both security headers and the absence of private project files.

What this does not prove

Automated checks reduce common mistakes; they do not replace monitoring, dependency maintenance, hosting-account protection, or a new review when interactive server-side features are introduced.