# Content Security Policy URL: /docs/advanced/csp/ Section: advanced Tags: advanced, security, csp -------------------------------------------------------------------------------- Content Security Policy Kida provides built-in CSP nonce injection for inline <script> and <style> tags. Nonces are automatically added to tags that don't already have one, keeping your templates compliant with strict Content Security Policy headers. Quick Start There are three ways to inject CSP nonces into rendered HTML: Standalone function -- post-process any HTML string Template filter -- apply nonces inside a template RenderContext metadata -- set a nonce once, read it anywhere during rendering from kida.utils.csp import inject_csp_nonce html = '<script>alert("hi")</script>' safe = inject_csp_nonce(html, "abc123") # '<script nonce="abc123">alert("hi")</script>' inject_csp_nonce() The core function. It scans HTML for opening <script> and <style> tags (case-insensitive) and inserts a nonce="..." attribute on every tag that doesn't already have one. from kida.utils.csp import inject_csp_nonce inject_csp_nonce('<script>x</script>', 'r4nd0m') # '<script nonce="r4nd0m">x</script>' # Tags that already have a nonce are left alone inject_csp_nonce('<script nonce="old">x</script>', 'new') # '<script nonce="old">x</script>' # Works on <style> tags too inject_csp_nonce('<style>.red{color:red}</style>', 'r4nd0m') # '<style nonce="r4nd0m">.red{color:red}</style>' The nonce value is HTML-escaped before insertion. If the input is a Markup instance, the return value is also Markup so autoescaped templates won't double-escape the result. An empty or None nonce is a no-op -- the HTML is returned unchanged. csp_nonce Filter Use the csp_nonce filter inside templates to inject nonces into a block of HTML content. {{ content | csp_nonce }} {{ content | csp_nonce("explicit-nonce-value") }} When called without an argument, the filter reads the nonce from the current RenderContext metadata (key csp_nonce). This lets you set the nonce once at the framework level and have every template pick it up automatically. The filter always returns Markup, so the result is safe for autoescaped templates. csp_nonce() Global A template global that returns the current nonce string from RenderContext metadata. Use it to manually add nonces to individual tags: <script nonce="{{ csp_nonce() }}"> // inline script </script> Returns an empty string if no nonce has been set. Framework Integration Setting the Nonce via RenderContext In any framework, you can set the CSP nonce on the RenderContext so that filters and globals pick it up automatically: from kida.render_context import render_context with render_context() as ctx: ctx.set_meta("csp_nonce", nonce_value) html = template.render(**data) # All <script> and <style> tags now have nonce attributes Flask Example import secrets from flask import Flask, make_response from kida.contrib.flask import init_kida from kida.render_context import render_context app = Flask(__name__) kida_env = init_kida(app) @app.route("/") def home(): nonce = secrets.token_urlsafe(16) template = kida_env.get_template("home.html") with render_context() as ctx: ctx.set_meta("csp_nonce", nonce) html = template.render(title="Home") response = make_response(html) response.headers["Content-Security-Policy"] = ( f"script-src 'nonce-{nonce}'; style-src 'nonce-{nonce}'" ) return response Django Example import secrets from django.http import HttpResponse from kida.render_context import render_context def home(request): nonce = secrets.token_urlsafe(16) from django.template import loader template = loader.get_template("home.html") with render_context() as ctx: ctx.set_meta("csp_nonce", nonce) html = template.render({"title": "Home"}, request) response = HttpResponse(html) response["Content-Security-Policy"] = ( f"script-src 'nonce-{nonce}'; style-src 'nonce-{nonce}'" ) return response Starlette / FastAPI Example import secrets from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse from kida.contrib.starlette import KidaTemplates from kida.render_context import render_context app = FastAPI() templates = KidaTemplates(directory="templates") @app.get("/") async def home(request: Request): nonce = secrets.token_urlsafe(16) template = templates.get_template("home.html") with render_context() as ctx: ctx.set_meta("csp_nonce", nonce) html = template.render(title="Home", request=request) return HTMLResponse( content=html, headers={ "Content-Security-Policy": ( f"script-src 'nonce-{nonce}'; style-src 'nonce-{nonce}'" ) }, ) See Also Security -- Sandboxing and autoescape Flask Integration -- Full Flask setup Django Integration -- Full Django setup Starlette & FastAPI Integration -- Full Starlette/FastAPI setup -------------------------------------------------------------------------------- Metadata: - Word Count: 554 - Reading Time: 3 minutes