Brew a Content Security Policy

Turn real page loads into a CSP you can ship.

cspresso crawls up to N same‑origin pages with headless Chromium (Playwright), watches the assets that load, and emits a draft Content-Security-Policy header.

--json --evaluate --bypass-csp --include-sourcemaps
pipx install cspresso
cspresso https://example.com --max-pages 10

# visited: https://example.com/
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; ...;
Remember: it’s only a starting point: crawls may not hit every flow, and inline hashing/nonces require care.

Quickstart

                  
cspresso https://mig5.net \
  --ignore-non-html \
  --max-pages 10
                  
                
What you’ll get
A header line you can paste into your vhost, or parseable info with --json

Tip: if an existing CSP might block loads during analysis, add --bypass-csp.
# Evaluate a candidate CSP (Report-Only) and fail CI on violations
cspresso https://mig5.net \
  --bypass-csp \
  --evaluate "default-src 'self'; img-src 'none';" \
  --json

{
  [...]
  "violations": [
    {
      "console": true,
      "disposition": "report",
      "documentURI": "https://mig5.net/",
      "text": "Loading the image 'https://mig5.net/logo.svg' violates the following Content Security Policy directive: \"img-src 'none'\". The policy is report-only, so the violation has been logged but no further action has been taken.",
      "type": "info"
    },
    {
      "console": true,
      "disposition": "report",
      "documentURI": "https://mig5.net/static/mig5.asc",
      "text": "Applying inline style violates the following Content Security Policy directive 'default-src 'self''. Either the 'unsafe-inline' keyword, a hash ('sha256-4Su6mBWzEIFnH4pAGMOuaeBrstwJN4Z3pq/s1Kn4/KQ='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback. The policy is report-only, so the violation has been logged but no further action has been taken.",
      "type": "info"
    }
  ]
}

# exit code: 1 if violations detected

How it works

cspresso lets the browser do the hard part: execute the page, watch what it loads, and distill origins into directives.

Crawl
Visit up to --max-pages same-origin pages and let the app’s JS run.
Observe
Track scripts, styles, images, fonts, frames, and “connect-like” requests.
Draft a CSP
Emit a baseline policy plus observed origins per directive.
Evaluate
Inject a candidate as Report‑Only and capture violations with an exit code for CI.
Inline script/style is tricky: nonces must be generated per response, and hashes must match bytes exactly. cspresso reports what it sees, but you should review and tighten before enforcing.

Popular flags

A few options that tend to matter in real deployments.

--bypass-csp
Strip existing CSP response headers so they don’t block discovery or evaluation.
--evaluate
Inject a candidate policy as Report‑Only and exit 1 if any violations are detected.
--include-sourcemaps
Heuristically discover sourcemap origins and add them to connect-src.
--upgrade-insecure-requests
Emit upgrade-insecure-requests in the proposed policy.
--browsers-path
Control where Playwright installs Chromium (handy for AppImage/CI caches).
--json
Machine-readable output: CSP, visited URLs, notes, and evaluation violations.

Install

pipx, pip, Poetry, or a standalone AppImage from Releases.

# Recommended
pipx install cspresso

# Or plain pip (use a venv)
pip install cspresso
Playwright browsers
cspresso can auto-install Chromium for Playwright if it isn’t present. By default it installs into ./.pw-browsers for deterministic builds and easy CI caching.

Override with --browsers-path or PLAYWRIGHT_BROWSERS_PATH.
poetry add cspresso
Linux deps
If Chromium won’t start due to missing libraries, try --with-deps (may require elevated privileges).
chmod +x cspresso.AppImage
./cspresso.AppImage https://example.com \
  --browsers-path "$HOME/.cache/cspresso/pw-browsers"
Tip
AppImages mount read-only - use --browsers-path to install browsers into a writable cache directory.

Verify releases with the mig5 GPG key (fingerprint 00AE817C24A10C2540461A9C1D7CDE0234DB458D).