Set security headers (2)

Set common security headers (X-XSS-Protection, X-Frame-Options, X-Content-Type-Options, Permissions-Policy, Referrer-Policy, Strict-Transport-Security, Content-Security-Policy).

Last updated Apr 23, 2026 If you want to get started quickly, click on the button below.

Deploy to Cloudflare

This creates a repository in your GitHub account and deploys the application to Cloudflare Workers.

To inject CSP nonces into inline <script> tags using HTMLRewriter, refer to this CSP nonce example.

export default {
    async fetch(request) {
        const DEFAULT_SECURITY_HEADERS = {
            /*
    Secure your application with Content-Security-Policy headers.
    Enabling these headers will permit content from a trusted domain and all its subdomains.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy
    "Content-Security-Policy": "default-src 'self' example.com *.example.com",
    */
            /*
    You can also set Strict-Transport-Security headers.
    These are not automatically set because your website might get added to Chrome's HSTS preload list.
    Here's the code if you want to apply it:
    "Strict-Transport-Security" : "max-age=63072000; includeSubDomains; preload",
    */
            /*
    Permissions-Policy header provides the ability to allow or deny the use of browser features, such as opting out of FLoC - which you can use below:
    "Permissions-Policy": "interest-cohort=()",
    */
            /*
    X-XSS-Protection header prevents a page from loading if an XSS attack is detected.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection
    */
            "X-XSS-Protection": "0",
            /*
    X-Frame-Options header prevents click-jacking attacks.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options
    */
            "X-Frame-Options": "DENY",
            /*
    X-Content-Type-Options header prevents MIME-sniffing.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options
    */
            "X-Content-Type-Options": "nosniff",
            "Referrer-Policy": "strict-origin-when-cross-origin",
            "Cross-Origin-Embedder-Policy": 'require-corp; report-to="default";',
            "Cross-Origin-Opener-Policy": 'same-site; report-to="default";',
            "Cross-Origin-Resource-Policy": "same-site",
        };
        const BLOCKED_HEADERS = [
            "Public-Key-Pins",
            "X-Powered-By",
            "X-AspNet-Version",
        ];

        let response = await fetch(request);
        let newHeaders = new Headers(response.headers);

        const tlsVersion = request.cf.tlsVersion;
        console.log(tlsVersion);
        // This sets the headers for HTML responses:
        if (
            newHeaders.has("Content-Type") &&
            !newHeaders.get("Content-Type").includes("text/html")
        ) {
            return new Response(response.body, {
                status: response.status,
                statusText: response.statusText,
                headers: newHeaders,
            });
        }

        Object.keys(DEFAULT_SECURITY_HEADERS).map((name) => {
            newHeaders.set(name, DEFAULT_SECURITY_HEADERS[name]);
        });

        BLOCKED_HEADERS.forEach((name) => {
            newHeaders.delete(name);
        });

        if (tlsVersion !== "TLSv1.2" && tlsVersion !== "TLSv1.3") {
            return new Response("You need to use TLS version 1.2 or higher.", {
                status: 400,
            });
        } else {
            return new Response(response.body, {
                status: response.status,
                statusText: response.statusText,
                headers: newHeaders,
            });
        }
    },
};
export default {
    async fetch(request): Promise<Response> {
        const DEFAULT_SECURITY_HEADERS = {
            /*
    Secure your application with Content-Security-Policy headers.
    Enabling these headers will permit content from a trusted domain and all its subdomains.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy
    "Content-Security-Policy": "default-src 'self' example.com *.example.com",
    */
            /*
    You can also set Strict-Transport-Security headers.
    These are not automatically set because your website might get added to Chrome's HSTS preload list.
    Here's the code if you want to apply it:
    "Strict-Transport-Security" : "max-age=63072000; includeSubDomains; preload",
    */
            /*
    Permissions-Policy header provides the ability to allow or deny the use of browser features, such as opting out of FLoC - which you can use below:
    "Permissions-Policy": "interest-cohort=()",
    */
            /*
    X-XSS-Protection header prevents a page from loading if an XSS attack is detected.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection
    */
            "X-XSS-Protection": "0",
            /*
    X-Frame-Options header prevents click-jacking attacks.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options
    */
            "X-Frame-Options": "DENY",
            /*
    X-Content-Type-Options header prevents MIME-sniffing.
    @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options
    */
            "X-Content-Type-Options": "nosniff",
            "Referrer-Policy": "strict-origin-when-cross-origin",
            "Cross-Origin-Embedder-Policy": 'require-corp; report-to="default";',
            "Cross-Origin-Opener-Policy": 'same-site; report-to="default";',
            "Cross-Origin-Resource-Policy": "same-site",
        };
        const BLOCKED_HEADERS = [
            "Public-Key-Pins",
            "X-Powered-By",
            "X-AspNet-Version",
        ];

        let response = await fetch(request);
        let newHeaders = new Headers(response.headers);

        const tlsVersion = request.cf.tlsVersion;
        console.log(tlsVersion);
        // This sets the headers for HTML responses:
        if (
            newHeaders.has("Content-Type") &&
            !newHeaders.get("Content-Type").includes("text/html")
        ) {
            return new Response(response.body, {
                status: response.status,
                statusText: response.statusText,
                headers: newHeaders,
            });
        }

        Object.keys(DEFAULT_SECURITY_HEADERS).map((name) => {
            newHeaders.set(name, DEFAULT_SECURITY_HEADERS[name]);
        });

        BLOCKED_HEADERS.forEach((name) => {
            newHeaders.delete(name);
        });

        if (tlsVersion !== "TLSv1.2" && tlsVersion !== "TLSv1.3") {
            return new Response("You need to use TLS version 1.2 or higher.", {
                status: 400,
            });
        } else {
            return new Response(response.body, {
                status: response.status,
                statusText: response.statusText,
                headers: newHeaders,
            });
        }
    },
} satisfies ExportedHandler;
from workers import WorkerEntrypoint, Response, fetch

class Default(WorkerEntrypoint):
    async def fetch(self, request):
        default_security_headers = {
            # Secure your application with Content-Security-Policy headers.
            #Enabling these headers will permit content from a trusted domain and all its subdomains.
            #@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy
            "Content-Security-Policy": "default-src 'self' example.com *.example.com",
            #You can also set Strict-Transport-Security headers.
            #These are not automatically set because your website might get added to Chrome's HSTS preload list.
            #Here's the code if you want to apply it:
            "Strict-Transport-Security" : "max-age=63072000; includeSubDomains; preload",
            #Permissions-Policy header provides the ability to allow or deny the use of browser features, such as opting out of FLoC - which you can use below:
            "Permissions-Policy": "interest-cohort=()",
            #X-XSS-Protection header prevents a page from loading if an XSS attack is detected.
            #@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection
            "X-XSS-Protection": "0",
            #X-Frame-Options header prevents click-jacking attacks.
            #@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options
            "X-Frame-Options": "DENY",
            #X-Content-Type-Options header prevents MIME-sniffing.
            #@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options
            "X-Content-Type-Options": "nosniff",
            "Referrer-Policy": "strict-origin-when-cross-origin",
            "Cross-Origin-Embedder-Policy": 'require-corp; report-to="default";',
            "Cross-Origin-Opener-Policy": 'same-site; report-to="default";',
            "Cross-Origin-Resource-Policy": "same-site",
        }
        blocked_headers = ["Public-Key-Pins", "X-Powered-By" ,"X-AspNet-Version"]

        res = await fetch(request)
        new_headers = res.headers

        # This sets the headers for HTML responses
        if "text/html" in new_headers["Content-Type"]:
            return Response(res.body, status=res.status, statusText=res.statusText, headers=new_headers)

        for name in default_security_headers:
            new_headers[name] = default_security_headers[name]

        for name in blocked_headers:
            del new_headers["name"]

        tls = request.cf.tlsVersion

        if not tls in ("TLSv1.2", "TLSv1.3"):
            return Response("You need to use TLS version 1.2 or higher.", status=400)
        return Response(res.body, status=res.status, statusText=res.statusText, headers=new_headers)
use std::collections::HashMap;
use worker::*;

#[event(fetch)]
async fn fetch(req: Request, _env: Env, _ctx: Context) -> Result<Response> {
    let default_security_headers = HashMap::from([
        //Secure your application with Content-Security-Policy headers.
        //Enabling these headers will permit content from a trusted domain and all its subdomains.
        //@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy
        (
            "Content-Security-Policy",
            "default-src 'self' example.com *.example.com",
        ),
        //You can also set Strict-Transport-Security headers.
        //These are not automatically set because your website might get added to Chrome's HSTS preload list.
        //Here's the code if you want to apply it:
        (
            "Strict-Transport-Security",
            "max-age=63072000; includeSubDomains; preload",
        ),
        //Permissions-Policy header provides the ability to allow or deny the use of browser features, such as opting out of FLoC - which you can use below:
        ("Permissions-Policy", "interest-cohort=()"),
        //X-XSS-Protection header prevents a page from loading if an XSS attack is detected.
        //@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection
        ("X-XSS-Protection", "0"),
        //X-Frame-Options header prevents click-jacking attacks.
        //@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options
        ("X-Frame-Options", "DENY"),
        //X-Content-Type-Options header prevents MIME-sniffing.
        //@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options
        ("X-Content-Type-Options", "nosniff"),
        ("Referrer-Policy", "strict-origin-when-cross-origin"),
        (
            "Cross-Origin-Embedder-Policy",
            "require-corp; report-to='default';",
        ),
        (
            "Cross-Origin-Opener-Policy",
            "same-site; report-to='default';",
        ),
        ("Cross-Origin-Resource-Policy", "same-site"),
    ]);
    let blocked_headers = ["Public-Key-Pins", "X-Powered-By", "X-AspNet-Version"];
    let tls = req.cf().unwrap().tls_version();
    let res = Fetch::Request(req).send().await?;
    let mut new_headers = res.headers().clone();

    // This sets the headers for HTML responses
    if Some(String::from("text/html")) == new_headers.get("Content-Type")? {
        return Ok(Response::from_body(res.body().clone())?
            .with_headers(new_headers)
            .with_status(res.status_code()));
    }
    for (k, v) in default_security_headers {
        new_headers.set(k, v)?;
    }

    for k in blocked_headers {
        new_headers.delete(k)?;
    }

    if !vec!["TLSv1.2", "TLSv1.3"].contains(&tls.as_str()) {
        return Response::error("You need to use TLS version 1.2 or higher.", 400);
    }
    Ok(Response::from_body(res.body().clone())?
        .with_headers(new_headers)
        .with_status(res.status_code()))

}
import { Hono } from "hono";
import { secureHeaders } from "hono/secure-headers";

const app = new Hono();
app.use(secureHeaders());

// Handle all other requests by passing through to origin
app.all("*", async (c) => {
    return fetch(c.req.raw);
});

export default app;

Was this helpful?

YesNo

On this page

Set security headers (2) - 图2Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers/examples/security-headers/#page","headline":"Set security headers","description":"Set common security headers (X-XSS-Protection, X-Frame-Options, X-Content-Type-Options, Permissions-Policy, Referrer-Policy, Strict-Transport-Security, Content-Security-Policy).","url":"https://developers.cloudflare.com/workers/examples/security-headers/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/examples/security-headers/og.png?v=90cf435b51afce1a","dateModified":"2026-04-23","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["Security","Middleware","JavaScript","TypeScript","Python","Rust"]}


description: Verify a signed request using the HMAC and SHA-256 algorithms or return a 403. title: Sign requests image: https://developers.cloudflare.com/workers/examples/signing-requests/og.png?v=0d3ca3dbd068b10b


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/workers/llms.txt
Use this file to discover all available pages before exploring further.