There’s no Python library for parsing Content Security Policy headers. I checked PyPI, I checked GitHub — nothing. Google has a CSP Evaluator web tool and an npm package, but if you want to analyze CSP programmatically in Python — for recon scripts, bug bounty automation, or CI pipelines — you’re on your own.

So I built one.

csp-toolkit is a Python library and CLI tool that parses CSP headers, runs 21 weakness checks, finds bypass vectors against a database of 79 known-exploitable domains, scores policies A+ to F, and does a lot more. The current release is v0.8.1 on PyPI (changelog, docs).

pip install csp-toolkit

What It Does

The core workflow is simple: give it a CSP, get back findings.

$ csp-toolkit analyze "script-src 'self' 'unsafe-inline' *.googleapis.com"

This outputs a severity-sorted table of findings, a letter grade, and a numeric score. The same thing works as a Python library:

import csp_toolkit

policy = csp_toolkit.parse("script-src 'self' 'unsafe-inline' *.googleapis.com")
findings = csp_toolkit.analyze(policy)
grade, score = csp_toolkit.score_policy(policy)
# F (35/100), 8 findings

But the analyzer is just the starting point. The tool exposes 15 CLI commands covering analysis, live fetch, bypass search, scanning, diffs, monitoring, auto-generated CSPs, violation reports, and more.

The Bypass Finder

The most useful feature for bug bounty is the bypass finder. It cross-references whitelisted domains in a CSP against a curated database of:

  • 66 JSONP domains with concrete callback URLs — Google (10+ subdomains), Facebook, Twitter, Yahoo, LinkedIn, Microsoft, GitHub, Spotify, Vimeo, Reddit, WordPress, Stripe, reCAPTCHA, and more
  • 13 CDN domains with 31 script gadgets — AngularJS template injection, Vue.js template injection, Knockout.js data-bind, Lodash/Underscore template RCE, Handlebars prototype pollution, jQuery selector XSS
  • 18+ arbitrary hosting domains where anyone can serve JS — raw.githubusercontent.com, codepen.io, vercel.app, netlify.app, pages.dev
$ csp-toolkit bypass "script-src 'self' *.googleapis.com cdnjs.cloudflare.com"

This outputs specific bypass vectors with concrete payloads. If a target whitelists *.googleapis.com in their script-src, the tool tells you exactly which JSONP endpoints on maps.googleapis.com, translate.googleapis.com, and accounts.google.com you can use — with ready-to-test <script src="..."> payloads.

You can also probe endpoints live with --check-live to verify they still respond.

How the Top 10 Websites Score

I pointed csp-toolkit at the top websites to see how their CSP policies hold up. The results are… mixed.

SiteGradeScoreFindingsBypassesNotable
GitHubA+9830Best in class. Nonce-based, strict-dynamic, all directives locked down.
RedditA9341Missing base-uri.
Twitter/XB8365JSONP via twimg.com, CSP2 downgrade vector.
LinkedInC7873Wildcards in img/media, JSONP via platform.linkedin.com.
GoogleD5392Report-only (not enforced), unsafe-eval, https: scheme.
YouTubeD5392Same as Google — testing policy, not enforcing.
InstagramF31137blob:, unsafe-eval, JSONP via facebook/google domains.
FacebookF26141212 bypass vectors. blob:, unsafe-eval, data: in frames.
NetflixF18112Report-only, unsafe-inline + unsafe-eval + https:.
AppleF8124unsafe-inline, unsafe-eval, blob:, data: everywhere.

GitHub is the clear winner — nonce-based CSP with strict-dynamic, all critical directives present, zero bypass vectors in our database. Facebook is the worst, with 12 known bypass vectors including JSONP endpoints on graph.facebook.com, connect.facebook.net, and whitelisted Google domains.

Google and YouTube are interesting: they have reasonably designed policies using nonces and strict-dynamic, but they’re only deployed as Content-Security-Policy-Report-Only — meaning violations are logged but not blocked. The policy provides zero actual protection.

Recon Workflow

For bug bounty, the typical workflow looks like this:

1. Batch scan your target list:

csp-toolkit scan -f targets.txt -o csv > results.csv

This fetches CSP from every URL, scores each one, and outputs a ranked table — weakest first. Focus on the F’s.

2. Check subdomains for variance:

csp-toolkit subdomains example.com

Tests ~35 common subdomains (www, api, staging, admin, etc.) and shows which ones have weaker CSP. A target might have a solid CSP on www.example.com but a wide-open policy on staging.example.com.

3. Deep-dive on weak targets:

csp-toolkit fetch https://weak-target.com --all
csp-toolkit bypass "their-csp-header-here" --check-live

4. Diff policies after deploys:

csp-toolkit diff https://target.com https://staging.target.com

Shows exactly what changed — added/removed directives, added/removed sources — and warns when changes weaken the policy.

5. Monitor for changes over time:

csp-toolkit monitor -f targets.txt  # run via cron
csp-toolkit history https://target.com

Stores snapshots and alerts when a target weakens their CSP — a new unsafe-inline, a removed directive, a new broad wildcard.

Violation reports and stacked policies (v0.6+)

If you collect CSP violation JSON (from a report-uri endpoint, Reporting API payloads, or browser exports), you can compare those reports to the policy you intend to enforce and get concrete fix hints.

violations groups reports by blocked URI and effective directive. With --csp or --csp-file, it suggests which source to add (or flags when the source is already allowed, including default-src fallback). In --fix-mode patch, it prints an additive patched CSP draft; --write-patch file.csp saves that draft for review before deploy.

csp-toolkit fetch https://example.com          # copy the live header into policy.txt
csp-toolkit violations reports.json --csp-file policy.txt --fix-mode patch --write-patch patched.csp

From Python: parse_violations_json, suggest_violation_fixes, and build_patched_csp are available on the top-level package.

When a response sends multiple Content-Security-Policy headers, browsers enforce their intersection. effective approximates that: pass a file with one CSP value per line (at least two lines) and it intersects literal source lists per directive.

csp-toolkit effective -f stacked-csp.txt -o json

CI gating and the GitHub Action (v0.8)

The opening line of this post says you might want CSP analysis “for recon scripts, bug bounty automation, or CI pipelines.” The first two worked from day one. The third didn’t — until now.

The problem with CSP in CI is that policies regress silently. Someone adds 'unsafe-inline' to unblock a third-party widget, it ships, and nobody notices until an XSS report lands months later. Nothing fails. There’s no build step that cares.

So analyze and fetch now gate:

# Fail the build if any finding is CRITICAL or HIGH
csp-toolkit analyze --fail-on high -f policy.txt

# Or hold a grade floor
csp-toolkit analyze --min-grade B -f policy.txt

# Against a live target, with a SARIF report for code scanning
csp-toolkit fetch https://staging.example.com --fail-on high --output csp.sarif -o sarif

Why a violated gate exits 3

This is the part I’d get wrong if I were moving fast, so it’s worth calling out.

The obvious choice is to exit 1 on failure, or 2 — and 2 is what I reached for first. It’s wrong. Click already uses exit code 2 for usage errors, which means a typo’d flag produces the same status as a genuine policy regression:

csp-toolkit analyze "$CSP" --fail-on hgih   # typo → exit 2
csp-toolkit analyze "$CSP" --fail-on high   # real regression → exit 2

A CI wrapper can’t tell those apart. The typo silently reads as “your CSP got worse,” you go hunting for a regression that doesn’t exist, and — worse — the misconfigured check keeps “failing correctly” forever without ever having analyzed anything.

So the gate exits 3: 1 is a runtime error, 2 is a usage error, 3 means the policy actually violated a gate. Three distinct states, three distinct codes. Without a gate flag, exit stays 0 and nothing changes for existing scripts.

The Action

Wrapping that up for GitHub:

permissions:
  contents: read
  security-events: write   # for SARIF upload

jobs:
  csp:
    runs-on: ubuntu-latest
    steps:
      - uses: sampsonc/csp_toolkit@v1
        with:
          url: https://staging.example.com
          fail-on: high
          min-grade: B

Findings land in GitHub’s code scanning UI as SARIF, so they show up as annotations rather than buried in log output. You can also point it at a policy string or a policy-file if your CSP lives in config and you’d rather check it before deploy than after.

One deliberate carve-out: Report-Only policies are never gated. They’re advisory by definition — gating on a policy the browser isn’t enforcing would fail builds for a header that can’t break anything. Their findings still show up in the report.

AI-assisted violation analysis (v0.7)

violations --ai-enhance sends the grouped violation summary to Claude for contextual explanation: what the blocked resource probably is, whether allowing it is reasonable, and what the fix costs you in policy strictness. --context <business-type> shapes the advice — a bank and a marketing site should not get the same answer about whether to allow a third-party analytics domain.

It’s optional (pip install csp-toolkit[ai]) and off by default. The deterministic checks are still the product; this is a layer on top for triage.

Other Features

  • Nonce reuse detection (nonce-check) — fetches a URL multiple times to check if the CSP nonce is static. A static nonce completely defeats nonce-based protection.
  • Header injection testing (header-inject) — tests CRLF injection vectors that could override the CSP header.
  • Report-URI analysis (report-uri) — checks if the CSP reporting endpoint is reachable and accepts violations.
  • Violation reports (violations) — summarize report JSON; optional CSP-aware suggestions and patched draft (--fix-mode patch, --write-patch).
  • Stacked CSP intersection (effective) — combine multiple enforced header values into one approximate policy.
  • CSP generator (generate) — outputs strict/moderate/permissive presets in header, meta tag, nginx, or Apache format.
  • Nuclei templates — 10 templates for scanning CSP at scale with ProjectDiscovery’s nuclei.
  • Chrome extension — shows the CSP grade on every page you visit.
pip install csp-toolkit

The tool is MIT licensed. Issues and PRs welcome.


See also: