Overview
Kayston’s Forge implements strict HTTP security headers to provide defense-in-depth against common web vulnerabilities. All headers are configured invercel.json and applied to every response by Vercel’s edge network.
These headers are applied at the CDN edge before responses reach the client, providing a strong security baseline for the static application.
Complete Headers Configuration
The application applies the following security headers to all routes:Header-by-Header Breakdown
X-Content-Type-Options: nosniff
Purpose: Prevents MIME type sniffing attacks- Strictly honor the
Content-Typeheader sent by the server - Not attempt to “sniff” or guess content types from file contents
- Block execution of JavaScript files served with non-executable MIME types
All static assets are served with correct MIME types, so this header provides strong protection against MIME confusion attacks.
X-Frame-Options: DENY
Purpose: Prevents clickjacking attacks by blocking all framing<iframe>, <frame>, <embed>, or <object> elements on any domain, including the application’s own origin.
Attack Prevention:
Clickjacking attacks involve:
- Attacker embeds victim site in transparent iframe
- Overlays deceptive UI elements
- User thinks they’re clicking attacker’s UI but actually clicking victim site
frame-ancestors 'none' in the Content-Security-Policy.
Referrer-Policy: strict-origin-when-cross-origin
Purpose: Controls how much referrer information is sent with requests| Scenario | Referrer Sent |
|---|---|
| Same-origin navigation | Full URL (path and query string) |
| Cross-origin HTTPS → HTTPS | Origin only (no path) |
| Cross-origin HTTPS → HTTP | No referrer (downgrade blocked) |
| Cross-origin same-protocol | Origin only |
- Prevents leaking sensitive URL parameters (e.g., tokens, IDs) to third-party domains
- Blocks referrer on HTTPS → HTTP downgrades (prevents credential leakage)
- Still provides origin for legitimate cross-origin requests (CORS, analytics)
This balances privacy (not leaking full URLs) with functionality (allowing referrer-based security checks).
Permissions-Policy
Purpose: Disables browser features and APIs not needed by the application| Feature | Blocked | Rationale |
|---|---|---|
camera=() | All access to camera | Not needed for developer tools |
microphone=() | All access to microphone | Not needed for developer tools |
geolocation=() | All location access | Privacy violation, not needed |
payment=() | Payment Request API | No payment functionality |
usb=() | WebUSB API | Not needed, potential malware vector |
magnetometer=() | Magnetometer sensor | Not needed, fingerprinting risk |
accelerometer=() | Accelerometer sensor | Not needed, fingerprinting risk |
- Reduces browser APIs available to XSS attackers
- Prevents permission prompt phishing
- Mitigates device fingerprinting vectors
- Signals security-conscious design to users
Strict-Transport-Security (HSTS)
Purpose: Forces HTTPS and prevents protocol downgrade attacksmax-age=31536000: Cache this policy for 365 days (1 year)includeSubDomains: Apply policy to all subdomainspreload: Eligible for browser HSTS preload lists
- SSL Stripping: Prevents MITM attackers from downgrading HTTPS → HTTP
- Mixed Content: Ensures all resources load over HTTPS
- Certificate Errors: Users cannot click through certificate warnings
Once a browser sees this header, it will refuse to connect over HTTP for the entire
max-age period, even if the user types http:// in the address bar.preload directive indicates the domain should be submitted to browser vendors’ HSTS preload lists:
- Chrome/Edge: https://hstspreload.org/
- Firefox: Uses Chrome’s list
- Safari: Uses Chrome’s list
Content-Security-Policy (CSP)
Purpose: Defines allowed sources for scripts, styles, images, and other resourcesdefault-src ‘self’
Fallback policy for all unspecified directives Means: By default, only load resources from the same origin. This sets a secure baseline. Any directive not explicitly specified inherits this policy.script-src ‘self’ ‘unsafe-inline’
Allowed sources for JavaScript'self': JavaScript files from the same origin'unsafe-inline': Inline<script>tags and event handlers
security.md:127-138.
Why This Is Accepted:
- The application is fully static with no server-side code execution
- All dynamic content rendering uses React’s XSS-safe JSX escaping
- High-risk preview features (HTML, Markdown) use sandboxed iframes
- No user-generated content is stored or rendered between sessions
style-src ‘self’ ‘unsafe-inline’
Allowed sources for CSS'self': Stylesheets from the same origin'unsafe-inline': Inline<style>tags andstyle=""attributes
- UI redressing attacks
- Data exfiltration via CSS injection (attribute selectors + background URLs)
- Clickjacking via absolute positioning overlays
CSS injection is mitigated by: no user-generated CSS, all styles are application-controlled, and X-Frame-Options prevents embedding.
img-src ‘self’ data: blob:
Allowed sources for images'self': Images from same origindata:: Data URLs (e.g.,data:image/png;base64,...)blob:: Blob URLs (e.g.,blob:https://...)
- Display QR codes (generated as data URLs)
- Show preview images (potentially loaded as blobs)
- Render static assets (favicon, icons from same origin)
- Tracking pixels
- EXIF/metadata exfiltration
- Mixed content issues
font-src ‘self’
Allowed sources for fonts Only same-origin fonts are allowed. This blocks:- Third-party font tracking (e.g., Google Fonts)
- Font fingerprinting
- Malicious font files (font parser exploits)
public/fonts/.
connect-src ‘self’
Allowed destinations for fetch, XHR, WebSocket, EventSource Only same-origin connections are allowed. This is critical for the privacy-first architecture:- Blocks all third-party API calls
- Prevents data exfiltration via fetch/XHR
- No analytics beacons or tracking endpoints
- No WebSocket connections to external services
Because the application is fully static with no backend APIs, even same-origin fetch requests will only retrieve static assets (which use
default-src).worker-src ‘self’
Allowed sources for Web Workers and Service Workers Only same-origin workers are allowed. The application uses:public/sw.js: Service worker for PWA offline caching- No Web Workers currently (may be added for heavy computations)
- Workers cannot be loaded from third-party CDNs
- No worker-based cryptocurrency miners
- No worker-based tracking scripts
frame-src ‘self’ blob:
Allowed sources for iframes'self': Iframes from same origin (not currently used)blob:: Blob URLs for sandboxed preview iframes
sandbox attribute provides additional isolation beyond CSP:
allow-scripts: Required for interactive previews- Missing
allow-same-origin: Prevents accessing parent window - Missing
allow-forms: Prevents form submission - Missing
allow-popups: Prevents opening new windows
frame-ancestors ‘none’
Allowed parents that can embed this page in a frame No framing is allowed from any origin. This is the modern CSP equivalent ofX-Frame-Options: DENY.
Relationship to X-Frame-Options:
Both headers are sent for defense-in-depth:
- Older browsers honor
X-Frame-Options - Modern browsers honor
frame-ancestors(CSP2) - If they conflict, CSP takes precedence
object-src ‘none’
Allowed sources for<object>, <embed>, and <applet>
All plugin-based content is blocked. This prevents:
- Flash exploits (legacy)
- Java applet exploits (legacy)
- PDF reader exploits
- Arbitrary plugin execution
Modern browsers are phasing out plugin support, but this header provides defense-in-depth for older browsers and enterprise environments.
base-uri ‘self’
Allowed values for<base href="">
Only same-origin base URLs are allowed. This prevents:
- Relative URL hijacking: Attacker injects
<base href="https://evil.com"> - All relative URLs in the page now resolve to attacker’s domain
- JavaScript files, stylesheets, and API calls now load from attacker
<base> tags, this prevents XSS attackers from injecting one to escalate their attack.
Testing Security Headers
You can verify these headers are applied correctly:1. Browser Developer Tools
- Open DevTools (F12)
- Navigate to Network tab
- Refresh the page
- Click on the document request (usually the first one)
- View Response Headers
2. Command Line (cURL)
3. Online Security Header Analyzers
Header Evolution and Deprecations
Deprecated Headers (Not Used)
X-XSS-Protection
Status: Deprecated, not included Reason: This header enabled browser-based XSS filters in Internet Explorer and older Chrome versions. Modern browsers have removed these filters because they introduced new vulnerabilities (XSS via filter bypass). Modern Alternative: Content-Security-Policy provides superior XSS protection.Future Considerations
Cross-Origin-Opener-Policy (COOP)
Status: Not yet implemented Potential Value: Isolates browsing context from cross-origin windowswindow.opener access if the app is opened from a cross-origin page. Low priority because:
- Application doesn’t use
window.opener - No sensitive operations depend on opener isolation
Cross-Origin-Embedder-Policy (COEP)
Status: Not yet implemented Potential Value: Required forSharedArrayBuffer and high-resolution timers
- Multi-threaded processing with SharedArrayBuffer
- High-precision timer-dependent crypto operations
Cross-Origin-Resource-Policy (CORP)
Status: Not yet implemented Potential Value: Prevents resources from being loaded cross-origin- All resources are static and non-sensitive
- No user-specific or privileged data in static assets
CSP Reporting (Future Enhancement)
Potential future addition for monitoring CSP violations:- Detecting XSS attempts in production
- Identifying misconfigured CSP directives
- Monitoring for inline script injection attempts
Security Header Best Practices
Lessons learned from this implementation:1. Defense in Depth
Multiple headers protect against the same attack vector:X-Frame-Options: DENY+frame-ancestors 'none'(clickjacking)- Specific directives +
default-src 'self'(resource loading)
2. Secure Defaults
Start with strictest possible policy and relax only when necessary:- Begin with
default-src 'none' - Add exceptions only for required functionality
- Document every exception and its rationale
3. Test Before Deploy
Every CSP change should be tested in development:4. Monitor and Iterate
Security headers are not “set and forget”:- Review quarterly for new browser features
- Update when adding new dependencies or features
- Track browser support and deprecations
Conclusion
Kayston’s Forge implements a comprehensive security header policy that:- Provides strong protection against clickjacking, MIME sniffing, and protocol downgrades
- Reduces attack surface by disabling unnecessary browser APIs
- Enforces strict resource loading policies via CSP
- Balances security with functionality (documented trade-offs)
All headers are version-controlled in
vercel.json and applied automatically by the CDN. No runtime configuration is required.