Skip to content
Back to skills

Apply Content Security Policy

ASecurity

Use when deploying a web application that serves HTML — especially one with user-generated content, third-party scripts, or inline JavaScript — to restrict what resources the browser may load or execute.

  • 4 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 8, 2026
ai-agentsjavascriptpythonrustgojavagitsecurity

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add jeffreytse/grimoire-core --skill apply-content-security-policy --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Apply Content Security Policy?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Apply Content Security Policy
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jeffreytse-apply-content-security-policy/badge)](https://www.skillsdirectory.com/skills/jeffreytse-apply-content-security-policy)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: apply-content-security-policy
description: Use when deploying a web application that serves HTML — especially one with user-generated content, third-party scripts, or inline JavaScript — to restrict what resources the browser may load or execute.
source: 'OWASP Content Security Policy Cheat Sheet (owasp.org/www-project-cheat-sheets); W3C CSP Level 3 spec; OWASP Top 10 2021 A05; CWE-693'
tags: [security, owasp, csp, content-security-policy, xss-mitigation, web, developer]
---

# Apply Content Security Policy

Reduce the impact of XSS and injection attacks by declaring a strict Content Security Policy that whitelists trusted script, style, and resource origins.

## Why This Is Best Practice

**Adopted by:** Mandated by PCI DSS v4.0 Requirement 6.2.4 and referenced in OWASP Top 10 2021 (A05:Security Misconfiguration). Google, GitHub, Stripe, and Twitter deploy strict CSP headers. Google's CSP Evaluator is used internally and publicly to audit policies. W3C Content Security Policy Level 3 is implemented across all major browsers (Chrome, Firefox, Safari, Edge).
**Impact:** CSP reduces the exploitability of XSS vulnerabilities — Google's security team (2016 study, "CSP Is Dead, Long Live CSP!") found that 94.72% of deployed CSP policies are bypassable, but a strict nonce-based or hash-based CSP eliminates inline script injection entirely. GitHub's adoption of strict-dynamic CSP reduced XSS-related bug bounty payouts significantly. Without CSP, any injected script executes with full page privileges.
**Why best:** `unsafe-inline` and `unsafe-eval` policies look like CSP but provide nearly zero protection — they pass scanners while blocking nothing meaningful. Nonce-based or hash-based strict CSP (using `strict-dynamic`) is the modern approach that actually blocks injected scripts while supporting legitimate inline scripts via one-time tokens.

Sources: OWASP CSP Cheat Sheet; W3C CSP Level 3; Google Security Blog "CSP Is Dead, Long Live CSP!" (2016); CWE-693

## Steps

1. **Start with a report-only policy to avoid breaking production** — set `Content-Security-Policy-Report-Only` first to observe violations without enforcement.

   ```http
   Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
   ```

   Collect violation reports for 1–2 weeks before switching to enforcing mode.

2. **Build a strict nonce-based policy** — generate a cryptographically random nonce per request, attach it to all `<script>` and `<style>` tags, and reference it in the header.

   ```python
   import secrets
   nonce = secrets.token_urlsafe(16)  # 128-bit random value
   # Attach to template context
   ```

   ```html
   <script nonce="{{ nonce }}">
     // legitimate inline script
   </script>
   ```

   ```http
   Content-Security-Policy:
     default-src 'self';
     script-src 'nonce-{nonce}' 'strict-dynamic';
     style-src 'nonce-{nonce}' 'self';
     object-src 'none';
     base-uri 'self';
     require-trusted-types-for 'script'
   ```

3. **Use `strict-dynamic` to allow dynamically loaded scripts** — `strict-dynamic` propagates trust from a nonced script to scripts it dynamically loads, eliminating the need to whitelist CDN URLs.

   ```http
   script-src 'nonce-{nonce}' 'strict-dynamic'
   ```

   Do NOT use `script-src 'unsafe-inline' https://cdn.example.com` — this is bypassable via any CDN-hosted JSONP or redirect endpoint.

4. **Lock down `object-src`, `base-uri`, and `form-action`** — these are frequently forgotten and allow bypass:

   ```http
   object-src 'none';      # blocks Flash and plugin injection
   base-uri 'self';        # blocks <base href> hijacking
   form-action 'self';     # blocks form exfiltration to attacker domains
   ```

5. **For hash-based CSP (alternative to nonces)** — compute SHA-256 of each inline script's exact content and include the hash:

   ```http
   script-src 'sha256-{hash_of_inline_script}' 'strict-dynamic'
   ```

   Useful for static pages where scripts don't change. Fragile if any whitespace changes.

6. **Set up violation reporting** — use the `report-to` directive (CSP Level 3) to collect real violations in production:

   ```http
   Content-Security-Policy: ...; report-to csp-endpoint
   Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-report"}]}
   ```

7. **Test with Google's CSP Evaluator** — paste your policy at `csp-evaluator.withgoogle.com` to detect bypasses before deployment.

## Rules

- Never use `unsafe-inline` or `unsafe-eval` in a production CSP — they negate most protection.
- Nonces must be regenerated per request — a static nonce is equivalent to no nonce.
- `strict-dynamic` requires a nonce or hash to anchor trust — it's not standalone.
- CSP is defense-in-depth against XSS, not a replacement for output encoding (see `prevent-xss`).

## Common Mistakes

- **Allowlisting entire CDN domains** (`script-src https://cdn.jsdelivr.net`) — any JSONP endpoint or open redirect on that CDN bypasses the policy. Use nonces or hashes instead.
- **Forgetting `object-src 'none'`** — `default-src 'self'` does NOT cover `object-src` in all browsers.
- **Deploying CSP Level 1 allowlist policies** — they are nearly universally bypassable per Google's research. Nonce-based is the minimum effective policy.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…