csp-toolkit
Parse, analyze, generate, and find bypasses in Content Security Policy headers.
A Python library and CLI tool for security researchers and bug bounty hunters. Auto-generate CSPs by crawling a website, analyze policies with 23 weakness checks, find bypasses against a database of 79 domains (66 JSONP + 13 CDNs), score policies A+ to F, emit a hardened policy, ratchet CI gates against a baseline, diff policies, detect nonce reuse, and more.
Background on why I built it and how the checks were chosen: csp-toolkit: CSP Header Analysis at Scale.
Install
pip install csp-toolkit
# or with uv
uv pip install csp-toolkit
CLI Commands
analyze — Check a CSP for weaknesses
# From a string
csp-toolkit analyze "script-src 'self' 'unsafe-inline' *.googleapis.com"
# From a file or stdin
csp-toolkit analyze -f policy.txt
curl -sI https://example.com | grep -i content-security-policy | cut -d: -f2- | csp-toolkit analyze -f -
# Output formats: table (default), detail, json
csp-toolkit analyze -o json "script-src 'self' 'unsafe-inline'"
# Analyze a Report-Only header
csp-toolkit analyze --report-only "default-src 'self'"
# CI gating: exit 3 if any finding is CRITICAL or HIGH
csp-toolkit analyze --fail-on high "script-src 'self' 'unsafe-inline'"
# CI gating: exit 3 if the policy grades below B
csp-toolkit analyze --min-grade B "script-src 'self'"
# Write SARIF to a file for upload to a code-scanning dashboard
csp-toolkit analyze -o sarif --output csp.sarif -f policy.txt
Outputs a severity-sorted findings table and an A+ to F grade with numeric score (0-100).
Exit codes: 0 success, 1 runtime error, 2 usage error, 3 a --fail-on or --min-grade
gate was violated. The distinct gate code lets CI tell a policy regression apart from a broken
invocation. Without a gate flag the command always exits 0.
Baseline ratcheting
--fail-on and --min-grade are absolute: a policy that already grades D fails on day one and
keeps failing, so the check gets removed. A baseline records what the policy looks like today and
gates only on findings that are not in it — so the gate is adoptable at any starting quality while
remediation proceeds on its own schedule.
# Record the current state once, then commit the file
csp-toolkit analyze -f policy.txt --baseline .csp-baseline.json --update-baseline
# Later runs: exit 3 only on findings the baseline does not already contain
csp-toolkit analyze -f policy.txt --baseline .csp-baseline.json
# Narrow the ratchet: only NEW critical/high findings fail the build
csp-toolkit analyze -f policy.txt --baseline .csp-baseline.json --fail-on high
With a baseline, --fail-on filters which new findings count rather than gating on the policy's
total state — a pre-existing HIGH does not fail the build, a newly introduced one does.
--min-grade stays absolute, because a grade floor is meant as a hard limit. Report-Only policies
are still never gated.
A baseline stores each finding's stable fingerprint plus its check id, severity and title, so the committed file is reviewable in a pull request. Fingerprints are derived from the check id, directive and subject — never the message text — so rewording a finding does not invalidate a baseline. When a finding is fixed, the run reports it as resolved and suggests re-recording to lock the improvement in.
fetch --baseline works the same way and keys entries by URL, so one file can cover several
deployed targets.
bypass — Find CSP bypass vectors
csp-toolkit bypass "script-src 'self' *.googleapis.com cdnjs.cloudflare.com"
csp-toolkit bypass -f policy.txt
csp-toolkit bypass -o json "script-src 'self' data: cdnjs.cloudflare.com"
# Probe JSONP endpoints to verify they're live
csp-toolkit bypass --check-live "script-src 'self' *.googleapis.com"
Checks whitelisted domains against known:
- JSONP endpoints — 66 domains with concrete callback URLs
- CDN script gadgets — AngularJS, Vue.js, Knockout, Lodash, Handlebars, Dojo, Mithril, jQuery, Ember, and more
- Arbitrary hosting platforms — raw.githubusercontent.com, unpkg.com, codepen.io, vercel.app, netlify.app, etc.
- Scheme abuse — data: and blob: payloads
- Missing directive exploitation — base-uri injection, form-action hijacking
fetch — Fetch and analyze live URLs
# Fetch CSP headers and meta tags
csp-toolkit fetch https://example.com
# Fetch + analyze + find bypasses
csp-toolkit fetch https://example.com --all
# Multiple URLs
csp-toolkit fetch https://example.com https://github.com --all
# Probe JSONP endpoints live
csp-toolkit fetch https://example.com --all --check-live
# Skip SSL verification
csp-toolkit fetch https://example.com --all --no-verify-ssl
# CI gating against a live target (exit 3 on a violated gate)
csp-toolkit fetch https://staging.example.com --fail-on high --min-grade B
# Fail when a target serves no CSP at all
csp-toolkit fetch https://example.com --fail-on-missing-csp
# Pool findings from every URL into one SARIF report
csp-toolkit fetch https://a.example.com https://b.example.com \
--analyze -o sarif --output csp.sarif
--fail-on and --min-grade imply --analyze, and use the same exit codes as
analyze (3 = gate violated). Report-Only policies are reported but never
gated — they are advisory by definition.
scan — Batch scan and rank targets
# Scan multiple URLs, ranked weakest-first
csp-toolkit scan https://google.com https://github.com https://facebook.com
# From a file of URLs
csp-toolkit scan -f targets.txt
# Export as CSV or JSON
csp-toolkit scan -f targets.txt -o csv > results.csv
csp-toolkit scan -f targets.txt -o json
diff — Compare two CSP policies
# Compare two CSP strings
csp-toolkit diff "script-src 'self' 'unsafe-inline'" "script-src 'self' 'nonce-abc' 'strict-dynamic'"
# Compare two live URLs
csp-toolkit diff https://example.com https://staging.example.com
# JSON output
csp-toolkit diff -o json "old csp" "new csp"
Shows score delta, added/removed/modified directives, and warns when changes weaken the policy.
subdomains — Find weak subdomains
# Check ~35 common subdomains
csp-toolkit subdomains example.com
# Custom prefixes
csp-toolkit subdomains example.com -p "www,api,staging,admin,internal"
# Export
csp-toolkit subdomains example.com -o json
monitor — Track CSP evolution over time
# Take snapshots and alert on changes
csp-toolkit monitor https://facebook.com https://github.com
# From a file of URLs (run via cron)
csp-toolkit monitor -f targets.txt
# View snapshot history
csp-toolkit history https://facebook.com
Stores snapshots in ~/.csp-toolkit/snapshots/. Alerts when policies are weakened, strengthened, or removed.
nonce-check — Detect static nonce reuse
csp-toolkit nonce-check https://target.com
csp-toolkit nonce-check https://target.com -n 10 # 10 requests
Fetches the URL multiple times and checks if the CSP nonce changes. A static nonce completely defeats nonce-based CSP protection.
The CLI distinguishes unreachable host (no HTTP responses) from CSP present but no nonce. In code, use NonceReuseStatus (ANALYZED, NO_NONCE, FETCH_FAILED) on the result of detect_nonce_reuse.
header-inject — Test for CSP header injection
csp-toolkit header-inject https://target.com
Tests CRLF injection vectors that could allow an attacker to inject or override CSP headers.
report-uri — Analyze reporting endpoints
csp-toolkit report-uri --url https://target.com
csp-toolkit report-uri "script-src 'self'; report-uri https://example.com/csp"
Checks if the report-uri / report-to endpoint is reachable and accepts CSP violation reports.
effective — Combine stacked enforced CSP headers
When a response sends multiple Content-Security-Policy headers, browsers enforce their intersection. This command approximates that by intersecting literal source lists per directive (with default-src fallback where applicable).
# File: one CSP value per line (at least two non-empty lines)
csp-toolkit effective -f stacked-csp.txt
csp-toolkit effective -f stacked-csp.txt -o json
violations — Summarize violation reports and suggest policy fixes
Reads JSON from a file (one object, an array, or csp-report-wrapped reports). Without a CSP, it only groups and counts violations. With --csp or --csp-file, it suggests which directive likely needs which source, checks whether that source is already allowed (including default-src fallback), and can emit a patched CSP draft.
# Grouped summary only
csp-toolkit violations reports.json
# Compare reports to your current policy (string or file)
csp-toolkit violations reports.json --csp "default-src 'self'; script-src 'self'"
csp-toolkit violations reports.json --csp-file policy.txt
# AI-enhanced analysis with explanations and recommendations
csp-toolkit violations reports.json --csp-file policy.txt --ai-enhance --context "e-commerce"
# Emit a draft policy with additive fixes (review before deploy)
csp-toolkit violations reports.json --csp-file policy.txt --fix-mode patch
# Write the draft to disk
csp-toolkit violations reports.json --csp-file policy.txt --fix-mode patch --write-patch patched.csp
# JSON: summary, suggestions, patched_csp (patch mode), ai_analysis (with --ai-enhance)
csp-toolkit violations reports.json --csp-file policy.txt --fix-mode patch --format json --ai-enhance
AI Enhancement (requires pip install anthropic and ANTHROPIC_API_KEY):
- Contextual Explanations: Understands why violations occur in business context
- Security Impact Assessment: Risk scoring with detailed reasoning
- Implementation Guidance: Step-by-step deployment recommendations
- Smart Recommendations: Business-aware policy suggestions beyond basic fixes
Workflow with a live site: fetch or copy the CSP first (csp-toolkit fetch https://example.com), save violation JSON from your browser or report-uri collector, then run violations with --csp-file. Inline/script violations may suggest 'unsafe-inline'; prefer nonces or hashes where possible.
explain — Show which directive actually governs each resource type
csp-toolkit explain "script-src 'nonce-a' 'strict-dynamic'; child-src https://cdn.example"
# Only the resource types that inherit from a fallback — where the surprises are
csp-toolkit explain -f policy.txt --inherited-only
# One resource type, by directive or friendly name
csp-toolkit explain -f policy.txt --resource worker-src
csp-toolkit explain -f policy.txt --resource workers
csp-toolkit explain -f policy.txt -o json
Resolves every resource type through its real CSP Level 3 fallback chain and labels each one
explicit, inherited, or unrestricted. This is how you catch a policy that looks strict
because script-src is strict while workers inherit a much looser child-src:
Resource Governed by Status Effective sources
workers worker-src → child-src inherited https://cdn.example
frames frame-src → child-src inherited https://cdn.example
scripts script-src explicit 'nonce-a' 'strict-dynamic'
Most fetch directives fall back to default-src, but not all of them do it directly —
worker-src goes through child-src then script-src, and frame-src through child-src.
Non-fetch directives (frame-ancestors, form-action, base-uri) do not fall back at all, so
their absence means unrestricted.
harden — Emit a tightened version of a policy
# Safe by default: skips anything that can break a page
csp-toolkit harden -f policy.txt
# Just the policy, for piping into a config file
csp-toolkit harden -f policy.txt -o header > policy.hardened.txt
# Attempt the breaking changes too
csp-toolkit harden -f policy.txt --level strict --allow-breaking
csp-toolkit harden -f policy.txt -o json
Every change is labelled with its risk, and nothing is applied silently:
| Risk | Meaning |
|---|---|
none |
A no-op for modern browsers — e.g. dropping 'unsafe-inline' that a nonce already causes CSP2+ browsers to ignore |
low |
Rarely breaks a page, and the breakage is obvious if it does — adding object-src 'none', upgrading http: to https: |
high |
Removes capability the page may rely on; requires --allow-breaking |
--level safe (the default) applies none and low changes: it removes inert keywords, adds the
directives that have no default-src fallback (object-src, base-uri, form-action), and pins
worker-src when workers would otherwise inherit a looser child-src. --level strict also
attempts the high-risk changes — removing 'unsafe-eval', script wildcards and data:/blob:
script sources, adding frame-ancestors 'none' and require-trusted-types-for 'script' — and
still needs --allow-breaking to apply them.
Hardening is idempotent and never lowers a policy's score. Two deliberate limits: it will not strip
'unsafe-inline' from script-src unless a nonce or hash is already present (use auto to
generate hashes for a real page first), and it leaves wildcards in non-script directives alone,
because it cannot know which origins your framing or images legitimately need. Those keep showing
up in analyze output.
auto — Auto-generate a CSP from a live website
# Crawl a page and generate a CSP based on its resources
csp-toolkit auto https://example.com
# Output as nginx or apache directive
csp-toolkit auto https://example.com -o nginx
csp-toolkit auto https://example.com -o apache
# Crawl deeper (follow same-origin links)
csp-toolkit auto https://example.com --depth 1
# Auto-generate nonces for inline scripts/styles (shows which tags need nonce="...")
csp-toolkit auto https://example.com --auto-nonce
# Use SHA-256 hashes for inline content (most secure, no HTML changes needed)
csp-toolkit auto https://example.com --hash
# Use a specific nonce value
csp-toolkit auto https://example.com --nonce my-server-nonce
# Analyze the generated CSP for weaknesses
csp-toolkit auto https://example.com --analyze
# JSON output with all discovered resources, hashes, and nonces
csp-toolkit auto https://example.com -o json
Discovers all external resources (scripts, styles, images, fonts, frames, forms, media) and generates a tailored CSP that whitelists exactly the origins the site needs.
Three modes for handling inline scripts/styles:
| Flag | Security | How it works |
|---|---|---|
--hash |
Highest | Computes SHA-256 of each inline block — browser verifies content matches |
--auto-nonce |
High | Generates a nonce, tells you which tags need nonce="..." added |
--nonce VALUE |
High | Same as auto-nonce but you provide the value |
| (default) | Low | Uses unsafe-inline with a warning |
generate — Generate a CSP from a preset
# Strict (nonce-based, recommended)
csp-toolkit generate --preset strict
csp-toolkit generate --preset strict --nonce my-random-nonce
# Moderate or permissive
csp-toolkit generate --preset moderate
csp-toolkit generate --preset permissive
# Add custom sources
csp-toolkit generate --preset moderate --add-source "script-src cdn.example.com"
# Output formats: header (default), meta, nginx, apache
csp-toolkit generate --preset strict -o nginx
csp-toolkit generate --preset strict -o apache
csp-toolkit generate --preset strict -o meta
Library Usage
import csp_toolkit
# Parse
policy = csp_toolkit.parse("script-src 'self' 'unsafe-inline' *.googleapis.com")
# Analyze + score
findings = csp_toolkit.analyze(policy)
grade, score = csp_toolkit.score_policy(policy)
print(f"{grade} ({score}/100), {len(findings)} findings")
# Find bypasses
bypasses = csp_toolkit.find_bypasses(policy)
for b in bypasses:
print(b) # [HIGH] JSONP bypass via maps.googleapis.com (in script-src)
# Resolve what actually governs each resource type
for r in csp_toolkit.explain_policy(policy):
print(r.resource, r.governed_by, r.status) # workers child-src inherited
# Emit a tightened policy, with the risk of each change
result = csp_toolkit.harden_policy(policy, level="safe")
print(result.hardened)
for change in result.changes:
print(change, change.risk) # - script-src: 'unsafe-inline' none
for change in result.skipped:
print("held back:", change, change.rationale)
# Compare against a recorded baseline
baseline = csp_toolkit.Baseline(targets={"policy": csp_toolkit.entry_for_policy(old_policy)})
comparison = csp_toolkit.compare_to_baseline(policy, baseline, "policy")
print(comparison.new_findings) # regressions only
print(comparison.resolved) # findings that were fixed
# Diff two policies
diff = csp_toolkit.diff_headers(old_csp, new_csp)
print(diff.weakened) # Directives that got weaker
print(diff.strengthened) # Directives that got stronger
# Scan multiple URLs
results = csp_toolkit.scan_urls(["https://example.com", "https://github.com"])
for r in results:
print(f"{r.url}: {r.grade} ({r.score})")
# Check subdomains
results = csp_toolkit.check_subdomains("example.com")
# Track evolution
snapshot, alert = csp_toolkit.take_snapshot("https://example.com")
if alert and alert.alert_type == "weakened":
print(f"CSP weakened! {alert.score_delta}")
# Detect nonce reuse (check result.status: ANALYZED, NO_NONCE, or FETCH_FAILED)
result = csp_toolkit.detect_nonce_reuse("https://example.com")
if result.status == csp_toolkit.NonceReuseStatus.ANALYZED and result.is_static:
print(f"Static nonce: {result.nonces_found[0]}")
# Check header injection
result = csp_toolkit.check_header_injection("https://example.com")
# Analyze report-uri
result = csp_toolkit.analyze_report_uri(policy)
# Violation reports: parse JSON, suggest fixes vs a policy, build patched draft
reports = csp_toolkit.parse_violations_json(open("reports.json").read())
suggestions = csp_toolkit.suggest_violation_fixes(reports, policy)
patched = csp_toolkit.build_patched_csp(policy, suggestions)
# Stacked policies (intersection heuristic)
combined, warnings = csp_toolkit.combine_enforced_header_policies(
["default-src 'self'", "script-src https://cdn.example.com"]
)
# Look up specific domains
csp_toolkit.check_domain_jsonp("accounts.google.com")
csp_toolkit.check_domain_gadgets("cdnjs.cloudflare.com")
# Generate
csp = csp_toolkit.CSPBuilder.strict(nonce="abc123").build()
# Fetch live
result = csp_toolkit.fetch_csp("https://example.com")
Analyzer Checks (23)
| Severity | Check |
|---|---|
| CRITICAL | unsafe-inline in script-src |
| CRITICAL | data: URI in script-src |
| CRITICAL | No script-src and no default-src |
| HIGH | unsafe-eval in script-src |
| HIGH | https: scheme in script-src (allows any HTTPS origin) |
| HIGH | Wildcard * in script-src/default-src |
| HIGH | blob: URI in script-src |
| HIGH | Missing object-src |
| HIGH | strict-dynamic without nonce/hash |
| MEDIUM | Missing base-uri |
| MEDIUM | Missing form-action |
| MEDIUM | Missing frame-ancestors |
| MEDIUM | Overly broad wildcard domains (*.googleapis.com, etc.) |
| MEDIUM | unsafe-hashes in script-src |
| MEDIUM | unsafe-inline + nonce/hash (CSP2 downgrade) |
| MEDIUM | data: in object-src/frame-src/child-src |
| MEDIUM | Missing worker-src inheriting a broader child-src |
| MEDIUM | Meta-delivered policy specifying ignored directives |
| LOW | unsafe-inline in style-src |
| LOW | http: scheme sources |
| LOW | IP address sources |
| INFO | Report-Only mode |
| INFO | Missing require-trusted-types-for |
| INFO | Missing navigate-to |
Bypass Database
- 66 JSONP domains (69 endpoints) — Google (10+), Facebook, Twitter, Yahoo, LinkedIn, Microsoft, GitHub, Wikipedia, Pinterest, Tumblr, Spotify, Vimeo, SoundCloud, Dailymotion, Reddit, WordPress, Bing, Stripe, reCAPTCHA, Cloudflare Turnstile, Mixpanel, Segment, Hotjar, Twitch, and more
- 13 CDN domains (31 gadgets) — cdnjs, jsDelivr, unpkg, googleapis, jQuery CDN, BootstrapCDN, BootCSS, Sina, StaticFile, Statically, gitcdn, RawGit, raw.githubusercontent.com
- Gadget libraries — AngularJS template injection, Vue.js template injection, Knockout.js data-bind, Lodash/Underscore template RCE, Handlebars prototype pollution, Dojo/Ember template injection, jQuery selector XSS, jQuery UI dialog XSS
- 18+ arbitrary hosting domains — raw.githubusercontent.com, codepen.io, jsfiddle.net, surge.sh, netlify.app, vercel.app, pages.dev, workers.dev, and more
GitHub Action
Gate pull requests on CSP quality and publish findings to GitHub code scanning. Writeup on the exit-code design and how to roll a gate out without breaking every build on day one: Fail the build when your CSP regresses.
name: CSP Check
on: [pull_request]
permissions:
contents: read
security-events: write # required 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
Analyze a policy string or file instead of a live URL:
- uses: sampsonc/csp_toolkit@v1
with:
policy-file: config/csp.txt
fail-on: critical
upload-sarif: false
| Input | Default | Description |
|---|---|---|
url |
— | URL to fetch and analyze |
policy |
— | CSP header string to analyze |
policy-file |
— | File containing a CSP header string |
fail-on |
high |
Fail if any finding is at or above this severity (critical…info, or none) |
min-grade |
— | Fail if the grade is below this letter (A+…F) |
fail-on-missing-csp |
false |
With url, fail when no CSP header is served |
baseline |
— | Gate on findings absent from this baseline file instead of the policy's absolute state |
update-baseline |
false |
Record findings to baseline and exit without gating |
bypass |
false |
Also run the JSONP/CDN bypass finder |
report-only |
false |
Treat policy/policy-file as a Report-Only header |
upload-sarif |
true |
Upload SARIF to code scanning (needs security-events: write) |
sarif-file |
csp-toolkit.sarif |
Where to write the SARIF report |
version |
latest |
csp-toolkit version from PyPI, or local to install from the checkout |
python-version |
3.12 |
Python used to run the tool |
Outputs: passed (true/false) and sarif-file. Exactly one of url, policy, or
policy-file must be set. Report-Only policies are never gated — they are advisory by
definition — but their findings still appear in the SARIF report. Requires csp-toolkit >= 0.8.0.
Ratcheting in CI
Gate an already-weak policy from day one without a remediation project first:
- uses: sampsonc/csp_toolkit@v1
with:
policy-file: config/csp.txt
baseline: .csp-baseline.json
fail-on: high # only NEW critical/high findings fail the build
Create the file once, locally, and commit it:
csp-toolkit analyze -f config/csp.txt --baseline .csp-baseline.json --update-baseline
git add .csp-baseline.json
When a finding gets fixed, the run says so and the baseline can be re-recorded to lock the improvement in — which turns the file into a visible record of the policy getting better.
Browser Extension
A Chrome extension that shows a CSP grade badge on every page you visit.
- Open
chrome://extensions/ - Enable "Developer mode"
- Click "Load unpacked" and select the
browser-extension/directory
The badge shows the CSP grade (A+ to F) with color coding. Click it to see the full findings list, score, and raw CSP header. All analysis runs locally — no network requests.
Nuclei Templates
10 templates for scanning CSP misconfigurations at scale with Nuclei:
# Scan a single target
nuclei -t nuclei-templates/ -u https://example.com
# Scan a list with httpx pipeline
cat subdomains.txt | httpx -silent | nuclei -t nuclei-templates/ -severity critical,high
# Broad scan, then deep analysis with csp-toolkit
nuclei -t nuclei-templates/ -l targets.txt -severity critical,high -o flagged.txt
cat flagged.txt | awk '{print $NF}' | sort -u | csp-toolkit scan -f - -o csv
| Template | Severity | Detects |
|---|---|---|
csp-missing |
Medium | No CSP header |
csp-unsafe-inline |
High | 'unsafe-inline' in script-src |
csp-unsafe-eval |
Medium | 'unsafe-eval' in script-src |
csp-wildcard-script |
High | Wildcard * in script-src |
csp-data-uri-script |
Critical | data: in script-src |
csp-https-scheme-script |
High | https: scheme in script-src |
csp-report-only |
Info | Report-Only without enforced CSP |
csp-missing-object-src |
Medium | Missing object-src |
csp-missing-base-uri |
Medium | Missing base-uri |
csp-broad-cdn-whitelist |
Medium | Broad CDN wildcards in script-src |
Development
Use active probes (fetch, scan, header-inject, nonce-check, bypass --check-live, etc.) only against systems you are authorized to test.
Release history: CHANGELOG.md. Security reporting and dependency notes: SECURITY.md.
Pushing a tag v* runs .github/workflows/publish.yml (tests, then PyPI upload via trusted publishing). Configure the publisher once under PyPI → csp-toolkit → Publishing.
# Install dev dependencies
uv sync --all-extras
# Run tests (303 tests)
uv run pytest -v
# Same coverage gate as CI (optional locally)
uv run pytest --cov=csp_toolkit --cov-fail-under=75 -q
# Lint and format check
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
Author
Built by Carl Sampson. More application security writing at chs.us.
Metadata
Release files for csp-toolkit 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| csp_toolkit-0.9.0.tar.gz | 199.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| csp_toolkit-0.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 283.3 kB
Release files / csp_toolkit-0.9.0.tar.gz
| Download URL | csp_toolkit-0.9.0.tar.gz |
|---|---|
| Size | 199.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
69678d77d632876201414c92db0bc8a1690f226b7b06b21d3891c5176832c5dc
|
|
BLAKE2b-256 checksum How to use checksums |
044f877636a88a6de2b31e2c9835dbb62f33caf4640f6f00332b5219d54360e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency logRelease files / csp_toolkit-0.9.0-py3-none-any.whl
| Download URL | csp_toolkit-0.9.0-py3-none-any.whl |
|---|---|
| Size | 83.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c9f24fa62d6ce26ef1f247cefdb5cf90d9be328ab01a86489e33d2c3ed9831a2
|
|
BLAKE2b-256 checksum How to use checksums |
f62488646b182d57f2891051b052ab9b0941cb12d10eddb6f7af2eab9dfd0ab5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency log