Fix security headers are not configured in SvelteKit

The application does not set the baseline security response headers. Without them a browser will not enforce HTTPS, will guess content types, and will allow the page to be framed. Headers set by a CDN or ingress are invisible to static analysis, so this rule reports lower confidence when it finds no header configuration at all.

medium likely SvelteKit CWE-693 / OWASP A05:2021

The vulnerable pattern in SvelteKit

MEDIUM possible Security headers are not configured A05:2021 src/hooks.server.ts:1:1 1 │ // Fixture: a SvelteKit service with the mistakes owlwarden should find. │ ~ no security headers configured here 2 │ // Endpoints are `+server.ts`; the handler receives a RequestEvent. 3 │ import type { Handle } from '@sveltejs/kit'

This finding comes from the SvelteKit fixture in the owlwarden test suite. Without these headers the browser enforces nothing: strict-transport-security forces HTTPS for future requests; content-security-policy limits which scripts and origins the page may load; x-content-type-options stops browsers guessing a response's content type; x-frame-options blocks clickjacking via framing; referrer-policy stops URLs leaking to third parties.

The corrected handler

Set them once in `hooks.server.ts`, which runs in front of every response.

export const handle: Handle = async ({ event, resolve }) => {
  const response = await resolve(event)
  response.headers.set('strict-transport-security', 'max-age=63072000; includeSubDomains')
  response.headers.set('content-security-policy', "default-src 'self'")
  response.headers.set('x-content-type-options', 'nosniff')
  response.headers.set('x-frame-options', 'DENY')
  response.headers.set('referrer-policy', 'strict-origin-when-cross-origin')
  return response
}

On a different runtime

The fix above is written for the runtime SvelteKit usually runs on. These are the runtimes where it would not run at all - an import that does not exist, or an API the host does not have - and what to write instead.

Workers and other fetch-API runtimes

Set them on the response in middleware. A config block the Node build reads is not evaluated on this runtime.

export default {
  async fetch(request: Request) {
    const response = await handle(request)
    const headers = new Headers(response.headers)
    headers.set('strict-transport-security', 'max-age=63072000; includeSubDomains')
    headers.set('content-security-policy', "default-src 'self'")
    headers.set('x-content-type-options', 'nosniff')
    headers.set('x-frame-options', 'DENY')
    headers.set('referrer-policy', 'strict-origin-when-cross-origin')
    return new Response(response.body, { status: response.status, headers })
  },
}

If you are not using SvelteKit

Set these response headers at the edge or in the app: strict-transport-security, content-security-policy, x-content-type-options, x-frame-options, referrer-policy.

Check your own repository

npx owlwarden scan
npx owlwarden explain security-headers-missing

Runs on your machine. No account, no telemetry, no network unless you ask. In CI, SARIF uploads to code scanning and the exit code is the gate.

Other SvelteKit checks

Rules with a tested SvelteKit example.

security-headers-missing for every framework / All rules / owlwarden