CSPctl Documentation
Complete guide to managing Content Security Policies with CSPctl
Installation
Install via Script (Recommended)
$HOME/.local/bin
(customizable with CSPCTL_INSTALL_DIR
)CSPCTL_VERSION=v0.3.3-dev curl ... | sh
Download Binary (v0.3.3-dev)
Download pre-built binaries for your platform:
Linux
macOS
Windows
Manual Installation
After downloading the binary for your platform:
# Extract the archive (Linux/macOS)tar -xzf cspctl-*.tar.gz
# Or for Windows (using PowerShell)tar -xzf cspctl-windows-x86_64.tar.gz
# Move to a directory in your PATHsudo mv cspctl /usr/local/bin/# Or add to user directorymkdir -p ~/.local/binmv cspctl ~/.local/bin/
# Verify installationcspctl --version
Quick Start
1. Initialize a Policy
2. Start the UI
3. Test Your Policy
4. Deploy
Core Concepts
Content Security Policy (CSP)
CSP is a security standard that helps prevent XSS attacks by controlling which resources can be loaded on your website. It works by sending a special HTTP header that tells browsers what sources of content are trusted.
Policy Directives
default-src
- Fallback for all resource typesscript-src
- Controls JavaScript sourcesstyle-src
- Controls CSS sourcesimg-src
- Controls image sourcesconnect-src
- Controls AJAX/WebSocket/EventSourcefont-src
- Controls font sourcesmedia-src
- Controls audio/video sourcesframe-src
- Controls iframe sources
Report-Only Mode
Test policies without breaking your site by using report-only mode. Violations are logged but not blocked, allowing you to fine-tune policies before enforcement.
Violation Reports
When CSP blocks a resource, it can send a JSON report to your specified endpoint. CSPctl provides real-time streaming of these reports with PII redaction options, helping you understand what resources are being blocked and adjust your policy accordingly.
Progressive Rollout
Deploy CSP changes gradually by controlling the percentage of traffic that receives the new policy. Start with 10%, monitor violations, then increase to 50% and eventually 100% as confidence grows.
Offline Caching
CSPctl automatically caches policies locally for resilience. If the API is unreachable, your application continues serving the last-known-good policy, ensuring security isn't compromised during outages.
AI-Powered Suggestions
Get intelligent recommendations for improving your CSP based on violation patterns and security best practices. CSPctl analyzes your reports and suggests additions or modifications to strengthen your policy.
Command Line Interface
Complete reference for all CSPctl CLI commands
Authentication
cspctl login
Set up authentication (displays setup instructions)
export CSPCTL_TOKEN=your-token
cspctl config set token your-token
cspctl ui
cspctl config set <key> <value>
Configure settings (valid keys: base, token)
base
- API base URL (default: http://127.0.0.1:5173)token
- Authentication tokenPolicy Management
cspctl init
Initialize a new CSP policy file with secure defaults
Creates csp.json with default-src: ['self'], script-src: ['self'], base-uri: ['none']
cspctl policy pull --app <app> -f <file>
Pull the current policy from the server (with automatic offline caching)
default-app
prod
(hardcoded)~/.cspctl/cache/{app}/prod/policy.json
csp.json
(short option: -f
)--json
- Output JSON to stdoutcspctl policy push --app <app> -f <file>
Push a policy to the server
default-app
prod
(hardcoded)csp.json
(short option: -f
)--json
- Output policy as JSONcspctl policy diff -f <file>
Show unified diff between local file and remote policy
csp.json
(short option: -f
)cspctl policy suggest --app <app> [--env <env>]
Get AI-powered suggestions based on violation reports
--app <app>
- Application IDprod
--apply
- Automatically apply suggestions to policy--export <path>
- Export suggestions to file--json
- Output as JSONHeaders & Security
cspctl header render -f <file> [--strict-dynamic] [--nonce <value>]
Generate CSP header from policy file
--strict-dynamic
- Add strict-dynamic to script-src--nonce <value>
- Use specific nonce (auto-generated if not specified)cspctl sri --path <file1,file2,...> [--algo <algorithm>]
Generate Subresource Integrity hashes
sha256
, sha384
(default), sha512
--json
for JSON outputfile.js\tsha384-hash...
cspctl nonce [--len <length>]
Generate a cryptographic nonce
Monitoring & Reports
cspctl reports --app <app> --env <env>
Stream CSP violation reports (real-time)
default-app
, env: prod
--filter <pattern>
- Filter by directive, URL, or app name--group-by <field>
- Group by: directive, host, path--pii-mode <mode>
- PII handling: none, redact (default: redact)--full
- Show full PII (deprecated, use --pii-mode none)--json
- Output as JSONcspctl suggestions --app <app> --env <env>
Get AI-powered policy improvement suggestions
--apply
- Apply suggestions to current policy--json
- Output as JSONDeployment & Rollout
cspctl rollout dry-run --app <app> [--env <env>] -f <file>
Test policy impact before deployment (returns mock data)
--no-fail
- Don't exit with code 10 if more than 20 requests would be blocked--json
- Output report as JSONcspctl rollout set --app <app> [--env <env>] --mode <mode> [--traffic <%>]
Configure rollout settings
prod
100
(percent)--json
- Output result as JSONUser Interface
cspctl ui [--port <port>]
Launch the web-based management UI
5173
--features ui
cspctl tui
Launch the terminal UI (Interactive mode)
help
, exit
, quit
, :q
REST API Reference
HTTP API for violation reporting and policy management
Authentication
API requests can include Bearer token authentication when available. The client API supports both authenticated and unauthenticated requests:
Token Configuration
CSPCTL_TOKEN
environment variabletoken
field in config file (~/.config/cspctl/config.toml)Base URL
cspctl config set base https://api.example.com
Offline Support
Endpoints
/api/policy?appId={app_id}&env={env}
Retrieve current policy for an application and environment
appId
- Application ID (required)env
- Environment name (required)
{ "policy": { "default_src": ["'self'"], "script_src": ["'self'", "cdn.example.com"], "style_src": ["'self'"], "img_src": [], "connect_src": [], "font_src": [], "frame_src": [], "object_src": [], "base_uri": ["'none'"], "report_to": "default" }, "id": "policy_123abc"}
/api/apps
List all applications
{ "apps": [ { "id": "app_123", "name": "My Application" } ]}
/api/apps
Create a new application
{ "name": "My New Application"}
{ "id": "app_456", "name": "My New Application"}
/api/reports/stream
Stream CSP violation reports (real-time)
app
- Application ID (required)env
- Environment name (required)filter
- Filter pattern (optional)group_by
- Group by: directive, host, path (default: directive)pii_mode
- PII handling: redact (default), full
{ "key": "script-src", // Group key "count": 5 // Number of violations}// Individual events include:// ts, url, blocked, app_id, app_name, ip
/api/rollout?appId={app_id}&env={env}
Get rollout configuration
{ "mode": "enforce", "traffic": 100}
/api/rollout
Configure rollout settings
{ "appId": "my-app", "env": "prod", "mode": "enforce", // Any string value "traffic": 25 // 0-100 percent}
/api/suggestions?appId={app_id}&env={env}
Get AI-powered policy suggestions
[ { "directive": "script-src", "source": "'strict-dynamic'", "count": 10, "confidence": 0.9, "reason": "Improve resilience" }, { "directive": "script-src", "source": "'nonce-…'", "count": 5, "confidence": 0.8, "reason": "Lock down inline" }]
/api/apply-suggestions
Apply suggestions to a policy
{ "policyId": "policy_123abc", "suggestions": [ { "directive": "script-src", "source": "'strict-dynamic'", "count": 10, "confidence": 0.9, "reason": "Improve resilience" } ]}
{ "id": "policy_456def"}
/api/rollout/dry-run
Simulate policy deployment impact
{ "app": "my-app", "env": "prod", "candidate": { "default_src": ["'self'"], "script_src": ["'self'"] }}
{ "blocked": 42, "top_hosts": [ ["cdn.bad", 21], ["img.bad", 10] ], "risky": ["'unsafe-inline'"]}
Rate Limits
- 1000 requests per hour for read operations
- 100 requests per hour for write operations
- Streaming endpoints count as 1 request per connection
Error Responses
401 Unauthorized
- Invalid or expired token403 Forbidden
- Insufficient permissions409 Conflict
- Version conflict, pull latest429 Too Many Requests
- Rate limit exceededSDK Support
Node.js / TypeScript
Python
Rust
Policy Configuration
Learn how to configure and manage CSP policies
Policy File Format
CSPctl uses JSON files to define policies. Each directive accepts an array of source expressions. Only the fields shown below are supported by the current Policy struct.
{ "default_src": ["'self'"], "script_src": [ "'self'", "'nonce-{NONCE}'", "https://cdn.jsdelivr.net", "https://unpkg.com" ], "style_src": [ "'self'", "'unsafe-inline'", "https://fonts.googleapis.com" ], "img_src": [ "'self'", "data:", "https:", "blob:" ], "font_src": [ "'self'", "https://fonts.gstatic.com" ], "connect_src": [ "'self'", "https://api.example.com", "wss://realtime.example.com" ], "frame_src": ["'none'"], "object_src": ["'none'"], "base_uri": ["'self'"], "form_action": ["'self'"], "frame_ancestors": ["'none'"], "upgrade_insecure_requests": true, "block_all_mixed_content": true}
default_src
script_src
style_src
img_src
connect_src
font_src
frame_src
object_src
base_uri
report_to
(Option<String>)Source Expressions
Keywords
'self'
- Same origin'none'
- Block all'unsafe-inline'
- Inline scripts/styles'unsafe-eval'
- eval() and similar'strict-dynamic'
- Trust script loads'unsafe-hashes'
- Event handlers
Schemes & Hosts
https:
- Any HTTPS sourcedata:
- Data URIsblob:
- Blob URLs*.example.com
- Wildcard subdomainexample.com:8080
- Specific port
Security Best Practices
Instead of 'unsafe-inline', use nonces or SHA hashes for inline scripts
Refactor code to avoid eval(), Function(), and setTimeout with strings
Use specific domains instead of broad wildcards or scheme-only sources
Always use HTTPS sources and enable upgrade-insecure-requests
Deploy in report-only mode first to identify issues before enforcement
Common Patterns
SPA with CDN
{ "default_src": ["'self'"], "script_src": ["'self'", "https://cdn.jsdelivr.net"], "style_src": ["'self'", "'unsafe-inline'"], "connect_src": ["'self'", "https://api.example.com"]}
E-commerce Site
{ "default_src": ["'self'"], "script_src": ["'self'", "https://checkout.stripe.com"], "frame_src": ["https://checkout.stripe.com"], "connect_src": ["'self'", "https://api.stripe.com"]}
Marketing Site with Analytics
{ "default_src": ["'self'"], "script_src": ["'self'", "https://www.google-analytics.com"], "img_src": ["'self'", "https://www.google-analytics.com"], "connect_src": ["'self'", "https://www.google-analytics.com"]}
Advanced Topics
Deep dive into advanced CSP features and techniques
Gradual Rollout
Deploy policies gradually to minimize risk and monitor impact on real traffic. CSPctl supports flexible rollout configurations with traffic percentage and mode controls.
Rollout Configuration
mode
: Any string value (commonly: "enforce", "report-only", "disabled")traffic
: Percentage from 0-100Dry Run Analysis
Nonce Generation
Use cryptographic nonces for inline scripts without unsafe-inline. CSPctl includes built-in nonce generation using Rust's secure random number generator.
Generate Nonces with CSPctl
rand::thread_rng().sample_iter(&Alphanumeric)
for secure generation.Server-side Integration (Node.js)
const crypto = require('crypto');
app.use((req, res, next) => { res.locals.nonce = crypto.randomBytes(16).toString('base64'); res.setHeader( 'Content-Security-Policy', `script-src 'nonce-${res.locals.nonce}'` ); next();});
// In your HTML template<script nonce="<%= nonce %>"> // Your inline script</script>
Subresource Integrity (SRI)
Ensure third-party resources haven't been tampered with.
Report Collection
Set up an endpoint to collect CSP violation reports.
// Express.js endpointapp.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => { const report = req.body['csp-report']; // Send to CSPctl fetch('https://api.cspctl.com/v1/reports', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify(report) }); res.status(204).send(); });
Integration Examples
Node.js / Express with CSPctl SDK
import express from 'express'import { nonceMiddleware, cspMiddleware, setConfig } from '@cspctl/node-sdk'
// Configure CSPctl SDKsetConfig({ base: process.env.CSPCTL_BASE || 'http://127.0.0.1:5173', appId: process.env.CSPCTL_APP_ID || 'myapp', env: process.env.CSPCTL_ENV || 'prod', token: process.env.CSPCTL_TOKEN, refreshSecs: 10, // Refresh policy every 10 seconds failOpenSecs: 300, // Use cache for 5 mins if API is down useSse: true // Use Server-Sent Events for real-time updates})
const app = express()
// Add nonce generation middlewareapp.use(nonceMiddleware())
// Add CSP header middleware with automatic policy fetchingapp.use(cspMiddleware({ mode: 'report-only', // Start with report-only strictDynamic: true // Add 'strict-dynamic' to script-src}))
app.get('/', (req, res) => { const nonce = res.locals.cspNonce res.send(` <script nonce="${nonce}"> console.log('This script is CSP-protected!') </script> `)})
app.listen(3000)
Rust / Axum with CSPctl SDK
use axum::{Router, middleware, routing::get};use cspctl_rust_sdk::{csp_layer, set_csp_config, CspSdkConfig};
#[tokio::main]async fn main() { // Configure CSPctl SDK set_csp_config(CspSdkConfig { base: std::env::var("CSPCTL_BASE").ok(), app_id: std::env::var("CSPCTL_APP_ID").ok(), env: std::env::var("CSPCTL_ENV").ok(), token: std::env::var("CSPCTL_TOKEN").ok(), refresh_secs: 10, fail_open_secs: 300, use_sse: true, });
// Build app with CSP middleware let app = Router::new() .route("/", get(handler)) .layer(middleware::from_fn(csp_layer));
// Start server let listener = tokio::net::TcpListener::bind("0.0.0.0:3000") .await .unwrap(); axum::serve(listener, app).await.unwrap();}
async fn handler(req: axum::http::Request<Body>) -> Html<String> { let nonce = nonce_from_request(&req).unwrap_or_default(); Html(format!( r#"<script nonce="{}">console.log('Protected!');</script>"#, nonce ))}
Next.js
// middleware.tsimport { NextResponse } from 'next/server'import type { NextRequest } from 'next/server'
export async function middleware(request: NextRequest) { const response = NextResponse.next() // Generate nonce const nonce = Buffer.from(crypto.randomUUID()).toString('base64') // Fetch policy from CSPctl API const policy = await fetch( `${process.env.CSPCTL_BASE}/api/policy?appId=${process.env.CSPCTL_APP_ID}&env=prod` ).then(r => r.json()) // Render CSP header with nonce const cspHeader = renderPolicy(policy, { nonce, strictDynamic: true }) response.headers.set('Content-Security-Policy', cspHeader) response.headers.set('X-CSP-Nonce', nonce) return response}
Nginx
# nginx.conflocation / { add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-$request_id'"; # Pass nonce to application proxy_set_header X-CSP-Nonce $request_id; proxy_pass http://upstream;}
Cloudflare Workers
addEventListener('fetch', event => { event.respondWith(handleRequest(event.request))})
async function handleRequest(request) { const response = await fetch(request) const newResponse = new Response(response.body, response) // Fetch policy from CSPctl const policy = await getPolicy() newResponse.headers.set('Content-Security-Policy', policy) return newResponse}
Deployment & CI/CD
Integrate CSPctl into your deployment pipeline
GitHub Actions
name: CSP Management
on: pull_request: paths: - 'csp-policies/**' push: branches: [main]
jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install CSPctl run: | curl -fsSL https://files.cspctl.com/uploads/releases/v0.3.3-dev/install.sh | sh echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Validate Policy run: | cspctl policy validate -f csp-policies/production.json - name: Dry Run Analysis run: | cspctl rollout dry-run \ --app ${{ vars.APP_ID }} \ --env staging \ -f csp-policies/production.json - name: Get AI Suggestions if: github.event_name == 'pull_request' run: | cspctl suggestions \ --app ${{ vars.APP_ID }} \ --env staging \ --output suggestions.json # Post suggestions as PR comment cat suggestions.json - name: Progressive Rollout if: github.ref == 'refs/heads/main' run: | # Deploy to staging first cspctl policy push \ --app ${{ vars.APP_ID }} \ --env staging \ -f csp-policies/production.json # Start production rollout at 10% cspctl rollout set \ --app ${{ vars.APP_ID }} \ --env production \ --mode enforce \ --traffic 10 # Monitor for 5 minutes sleep 300 # Check violation rate VIOLATIONS=$(cspctl reports \ --app ${{ vars.APP_ID }} \ --env production \ --json | jq '.count') if [ "$VIOLATIONS" -lt 100 ]; then # Increase to 50% cspctl rollout set \ --app ${{ vars.APP_ID }} \ --env production \ --traffic 50 fi
Complete Workflows
End-to-end examples of common CSPctl workflows
New Project Setup
Setting up CSP for a new project requires careful planning and iterative refinement. This guide walks you through the complete process from initial policy creation to production deployment.
Phase 1: Initial Policy Creation
Start with a restrictive baseline policy. It's easier to loosen restrictions based on actual needs than to tighten them after deployment.
# Initialize with secure defaultscspctl init
# This creates csp.json with:# - default-src: ['self']# - script-src: ['self'] # - base-uri: ['none']# - object-src: ['none']
Phase 2: Visual Policy Customization
Use the interactive UI to understand and modify your policy. The visual editor helps prevent syntax errors and provides immediate feedback on policy implications.
# Launch the web UI on port 5173cspctl ui
# Navigate to http://localhost:5173# The UI provides:# - Visual policy editor with syntax highlighting# - Real-time validation# - Directive documentation# - Common pattern templates
Common Additions for Modern Apps:
- • CDN for assets:
script-src 'self' cdn.jsdelivr.net
- • Analytics:
connect-src 'self' *.google-analytics.com
- • Fonts:
font-src 'self' fonts.googleapis.com
- • Images:
img-src 'self' data: https:
Security Considerations:
- • Avoid
'unsafe-inline'
- use nonces instead - • Avoid
'unsafe-eval'
- refactor code if needed - • Never use
*
as a source - • Always specify
https:
for external sources
Phase 3: Impact Analysis
Before deploying, analyze how your policy would affect your application. The dry-run feature simulates deployment and predicts potential issues.
# Run impact analysiscspctl rollout dry-run --app myapp -f csp.json
# Example output:# {# "blocked": 42,# "top_hosts": [# ["cdn.unauthorized.com", 21],# ["tracking.adnetwork.com", 10]# ],# "risky": ["'unsafe-inline' in script-src"]# }
- • More than 20 blocked requests: Policy may be too restrictive
- • Risky tokens detected: Security vulnerability potential
- • Unknown hosts in top_hosts: Possible third-party dependencies
Phase 4: Local Testing
Generate the actual CSP header and test it locally with your development server before deployment.
# Generate CSP header with strict-dynamic and noncecspctl header render -f csp.json --strict-dynamic
# Output example:# default-src 'self'; script-src 'self' 'nonce-Nc3n83cnSAd' 'strict-dynamic'; # style-src 'self' 'unsafe-inline'; base-uri 'none'; object-src 'none'
Testing in Your Application:
// Express.js exampleapp.use((req, res, next) => { // Generate nonce for each request const nonce = crypto.randomBytes(16).toString('base64'); // Apply CSP header res.setHeader( 'Content-Security-Policy-Report-Only', `default-src 'self'; script-src 'self' 'nonce-${nonce}' 'strict-dynamic'` ); // Make nonce available to templates res.locals.nonce = nonce; next();});
Phase 5: Staged Deployment
Deploy your policy gradually, starting with report-only mode to collect violation data without breaking functionality.
# Step 1: Deploy to staging in report-only modecspctl policy push --app myapp-staging -f csp.jsoncspctl rollout set --app myapp-staging --mode report-only --traffic 100
# Step 2: Monitor for 24-48 hourscspctl reports --app myapp-staging --env prod# Watch for unexpected violations
# Step 3: Analyze and adjustcspctl policy suggest --app myapp-staging --env prod --export suggestions.json# Review suggestions and update policy
# Step 4: Progressive production rolloutcspctl policy push --app myapp -f csp.jsoncspctl rollout set --app myapp --mode enforce --traffic 10 # 10% of users# Monitor for issues...cspctl rollout set --app myapp --mode enforce --traffic 50 # 50% of users# Continue monitoring...cspctl rollout set --app myapp --mode enforce --traffic 100 # Full deployment
Success Metrics
Your CSP deployment is successful when:
- ✓ Violation rate drops below 0.1% of page loads
- ✓ No legitimate functionality is blocked
- ✓ All third-party dependencies are explicitly allowed
- ✓ No unsafe-inline or unsafe-eval directives remain
- ✓ Monitoring is in place for ongoing violations
Debugging CSP Violations
CSP violations are your security policy working as intended, but they can also indicate legitimate resources being blocked. This guide helps you investigate, understand, and resolve violations systematically.
Understanding Violation Reports
Each violation report contains crucial information about what was blocked and why. Understanding these reports is key to refining your policy.
Anatomy of a Violation Report:
{ "blocked-uri": "https://evil-script.com/malware.js", "violated-directive": "script-src", "effective-directive": "script-src", "original-policy": "default-src 'self'; script-src 'self'", "document-uri": "https://myapp.com/dashboard", "referrer": "https://myapp.com/login", "status-code": 200, "source-file": "https://myapp.com/js/app.js", "line-number": 142, "column-number": 15}
🚨 Critical Fields
- blocked-uri: What resource was blocked
- violated-directive: Which CSP rule was violated
- document-uri: Where the violation occurred
🔍 Debug Fields
- source-file: Which script triggered the violation
- line-number: Exact location in code
- referrer: Previous page (useful for flows)
Step 1: Real-Time Monitoring
Start by streaming violations in real-time to understand the current state of your application.
# Stream all violations as they happencspctl reports --app myapp --env prod
# Example output (grouped by directive):# script-src: 42 violations# img-src: 15 violations# connect-src: 8 violations# font-src: 2 violations
- • High volume from single source = Likely legitimate dependency
- • Random/varied sources = Possible injection attempts
- • Sudden spike = New feature or attack
Step 2: Pattern Analysis
Group and filter violations to identify patterns and prioritize fixes.
Filter by Directive Type:
# Focus on script violations (most critical)cspctl reports --app myapp --filter script-src
# Common script-src violations:# - Third-party analytics (Google Analytics, Mixpanel)# - Chat widgets (Intercom, Zendesk)# - Payment processors (Stripe, PayPal)# - CDN libraries not explicitly allowed
Group by Host to Find Patterns:
# See which hosts are most frequently blockedcspctl reports --app myapp --group-by host
# Example output:# www.googletagmanager.com: 156 violations# fonts.googleapis.com: 89 violations# cdn.segment.com: 45 violations# unknown-tracker.com: 2 violations <-- Suspicious!
Group by Path for Specific Pages:
# Identify which pages have the most violationscspctl reports --app myapp --group-by path
# Helps identify:# - Pages with unique dependencies# - Legacy code that needs updating# - Third-party integrations on specific routes
Step 3: Deep Investigation
For complex violations, export detailed reports for analysis.
# Export full violation details (includes PII)cspctl reports --app myapp --full --json > violations-full.json
# Analyze with jqcat violations-full.json | jq '.[] | select(.blocked | contains("googleapis"))'
# Count unique blocked URIscat violations-full.json | jq -r '.blocked' | sort | uniq -c | sort -rn
Step 4: AI-Powered Resolution
Leverage AI suggestions to automatically identify safe additions to your policy based on violation patterns.
# Get AI suggestions based on violationscspctl policy suggest --app myapp --env prod
# Example suggestions:# [# {# "directive": "script-src",# "source": "https://www.googletagmanager.com",# "confidence": 0.95,# "reason": "Consistent violations from analytics setup"# },# {# "directive": "font-src",# "source": "https://fonts.gstatic.com",# "confidence": 0.98,# "reason": "Google Fonts dependency detected"# }# ]
High Confidence (>0.9)
Usually safe to add. Common services, CDNs, and well-known dependencies.
Low Confidence (<0.7)
Review manually. Could be tracking scripts, compromised resources, or attacks.
Step 5: Test and Deploy Fixes
Before applying changes, test the impact and deploy gradually.
# 1. Export current and suggested policiescspctl policy pull --app myapp -f current.jsoncspctl policy suggest --app myapp --export suggested.json
# 2. Review the differencesdiff -u current.json suggested.json
# 3. Test the new policy impactcspctl rollout dry-run --app myapp -f suggested.json
# 4. If safe (blocked count doesn't increase), apply changescspctl policy suggest --app myapp --applycspctl policy push --app myapp -f csp.json
# 5. Deploy with gradual rolloutcspctl rollout set --app myapp --mode enforce --traffic 10# Monitor for new violations...cspctl rollout set --app myapp --mode enforce --traffic 100
🎯 Common Violation Resolutions
Move to external files or use nonces. Never add 'unsafe-inline'.
Add specific domains, not wildcards. Consider self-hosting critical resources.
Use 'strict-dynamic' with nonces for legitimate dynamic scripts.
Add 'data:' to img-src for base64 images, but be cautious with other directives.
Implementing Subresource Integrity
Subresource Integrity (SRI) ensures that resources your application fetches (like scripts or stylesheets) haven't been tampered with. It's your last line of defense against compromised CDNs, supply chain attacks, and man-in-the-middle modifications.
Understanding SRI Protection
SRI works by comparing a cryptographic hash of the fetched resource against a known good hash. If they don't match, the browser blocks the resource, preventing potentially malicious code from executing.
✅ Protected Against
- • CDN compromises (e.g., CDN gets hacked)
- • Supply chain attacks (dependency tampering)
- • MITM attacks (network-level modification)
- • Accidental CDN updates breaking your app
⚠️ Limitations
- • Only works for CORS-enabled resources
- • Requires updating hashes when files change
- • Can't protect dynamically generated content
- • No protection for first-party resources
Step 1: Generate SRI Hashes
CSPctl can generate SRI hashes for your static resources. Choose your hash algorithm based on security needs (sha384 recommended, sha512 for critical resources).
# Generate hashes for specific filescspctl sri --path dist/js/app.js,dist/js/vendor.js --algo sha384
# Output:# dist/js/app.js sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC# dist/js/vendor.js sha384-MBO9IDwOL7XdrMp3rJhiP3NOMJdUJ6pFmPwLgW2T7kE4qJphH0RTEgN8w7dGsqrQ
# Generate for all JS files with JSON output (for build automation)cspctl sri --path "dist/**/*.js" --algo sha384 --json > sri-hashes.json
# Generate multiple algorithm hashes (for fallback support)cspctl sri --path dist/critical.js --algo sha256,sha384,sha512
# Output:# dist/critical.js sha256-RmX... sha384-oqV... sha512-9/u...
- • sha256: Fastest, adequate for most resources
- • sha384: Best balance of security and performance (recommended)
- • sha512: Maximum security for critical resources
Step 2: Implement in HTML
Add the integrity attribute to your script and link tags. Always include crossorigin="anonymous" for resources loaded from different origins.
Basic Implementation:
<!-- JavaScript with SRI --><script src="https://cdn.example.com/app.js" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="anonymous"></script>
<!-- CSS with SRI --><link rel="stylesheet" href="https://cdn.example.com/styles.css" integrity="sha384-MBO9IDwOL7XdrMp3rJhiP3NOMJdUJ6pFmPwLgW2T7kE4qJphH0RTEgN8w7dGsqrQ" crossorigin="anonymous">
<!-- Multiple hashes for browser compatibility --><script src="https://cdn.example.com/critical.js" integrity="sha256-RmX... sha384-oqV... sha512-9/u..." crossorigin="anonymous"></script>
Fallback Strategy:
<!-- Primary CDN with SRI --><script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" integrity="sha384-vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK" crossorigin="anonymous"></script>
<!-- Fallback to local copy if CDN fails integrity check --><script> // Check if jQuery loaded successfully if (typeof jQuery === 'undefined') { document.write('<script src="/js/vendor/jquery.min.js"><\/script>'); }</script>
Step 3: Automate in Build Pipeline
Integrate SRI generation into your build process to automatically update hashes when files change. This ensures your integrity checks always match your current resources.
// webpack.config.js - Webpack SRI Pluginconst { SubresourceIntegrityPlugin } = require('webpack-subresource-integrity');
module.exports = { output: { crossOriginLoading: 'anonymous', }, plugins: [ new SubresourceIntegrityPlugin({ hashFuncNames: ['sha384'], enabled: process.env.NODE_ENV === 'production', }), ],};
// build.js - Custom build scriptconst { execSync } = require('child_process');const fs = require('fs');
// Generate SRI hashes after buildconst sriOutput = execSync( 'cspctl sri --path dist/**/*.js --algo sha384 --json').toString();
const sriHashes = JSON.parse(sriOutput);
// Update HTML templates with SRI hasheslet html = fs.readFileSync('dist/index.html', 'utf8');for (const [file, hash] of Object.entries(sriHashes)) { const filename = file.split('/').pop(); html = html.replace( new RegExp(`src="[^"]*${filename}"`, 'g'), `src="/${file}" integrity="${hash}" crossorigin="anonymous"` );}fs.writeFileSync('dist/index.html', html);
Step 4: Monitor and Maintain
SRI requires ongoing maintenance as your dependencies update. Set up monitoring to detect when resources fail integrity checks.
// sri-monitor.js - Monitor for SRI failureswindow.addEventListener('error', (e) => { if (e.target && e.target.integrity) { // SRI failure detected console.error('SRI failure:', e.target.src || e.target.href); // Report to monitoring service fetch('/api/sri-failure', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ resource: e.target.src || e.target.href, integrity: e.target.integrity, timestamp: new Date().toISOString(), userAgent: navigator.userAgent, }), }); // Attempt fallback if configured const fallbackUrl = e.target.dataset.fallback; if (fallbackUrl) { const newElement = e.target.cloneNode(); newElement.src = fallbackUrl; newElement.integrity = e.target.dataset.fallbackIntegrity; e.target.parentNode.replaceChild(newElement, e.target); } }}, true);
🚀 Advanced SRI Strategies
For dynamically loaded resources, store SRI hashes in a manifest and verify before loading:
// Dynamic loading with SRIasync function loadScript(url, hash) { const script = document.createElement('script'); script.src = url; script.integrity = hash; script.crossOrigin = 'anonymous'; document.head.appendChild(script); return new Promise((resolve, reject) => { script.onload = resolve; script.onerror = reject; });}
Always use exact versions in CDN URLs. Never use "latest" or version ranges with SRI:
- ✅ Good:
https://cdn.../jquery@3.6.0/...
- ❌ Bad:
https://cdn.../jquery@latest/...
Combine SRI with CSP's require-sri-for directive to enforce integrity checking:
require-sri-for script style;
Offline Development
CSPctl provides robust offline capabilities through intelligent caching, allowing you to continue working without internet connectivity. This is crucial for airplane coding, restricted environments, or when your API endpoints are temporarily unavailable.
How Offline Mode Works
Every time you interact with remote policies, CSPctl automatically caches them locally. When network connectivity is lost, the CLI seamlessly switches to cached data, ensuring uninterrupted workflow.
📁 Cache Structure
✨ Cached Operations
- • Policy retrieval and viewing
- • Report analysis (historical data)
- • Header generation
- • Dry-run simulations
- • SRI hash generation
- • Local policy validation
Step 1: Building Your Cache
Before going offline, ensure you have the latest data cached. CSPctl automatically caches on every network operation, but you can also explicitly prepare for offline work.
# Prepare for offline work - cache all environmentsfor env in dev staging prod; do echo "Caching $env environment..." cspctl policy pull --app myapp --env $env -f /tmp/cache-$env.json cspctl reports --app myapp --env $env --limit 1000 --json > /dev/nulldone
# Verify cache is populatedls -la ~/.cspctl/cache/myapp/# dev/# staging/# prod/
# Check cache freshnessfind ~/.cspctl/cache -name ".timestamp" -exec sh -c 'echo "{}:"; cat {}' \;# Shows when each cache was last updated
Step 2: Working Offline
When offline, CSPctl automatically detects the lack of connectivity and switches to cached mode. You'll see notifications about offline status but can continue working normally.
Policy Operations:
# Pull policy (uses cache when offline)cspctl policy pull --app myapp -f policy.json# ℹ️ Offline mode: using cached policy from 2024-01-15 14:30:22
# View policy detailscspctl policy show -f policy.json
# Generate headers from cached policycspctl header render -f policy.json# Content-Security-Policy: default-src 'self'; script-src 'self' 'strict-dynamic';
# Validate policy syntax (fully offline)cspctl policy validate -f policy.json# ✅ Policy validation passed
Report Analysis:
# Analyze cached reportscspctl reports --app myapp --env prod --offline# ℹ️ Using cached reports (1,247 violations from last sync)
# Filter and analyze offlinecspctl reports --app myapp --filter script-src --group-by host --offline# Grouped analysis from cached data...
# Export for deeper analysiscspctl reports --app myapp --json --offline > analysis.jsonjq '.[] | select(.directive == "img-src")' analysis.json
Testing and Simulation:
# Run dry-run simulations offlinecspctl rollout dry-run --app myapp -f new-policy.json --offline# Simulating based on cached violation patterns...# Estimated impact: 23 additional blocks
# Generate SRI hashes (fully offline)cspctl sri --path dist/**/*.js --algo sha384# Works entirely offline - no network needed
# Test policy changes locallycspctl policy diff -f old.json -f new.json# Shows changes between two local policy files
Step 3: Advanced Offline Workflows
Leverage offline mode for complex development scenarios, including policy development, testing, and preparation for deployment.
#!/bin/bash# offline-dev.sh - Complete offline development workflow
# 1. Create development policy from cachecspctl policy pull --app myapp --env prod -f base.json --offlinecp base.json dev-policy.json
# 2. Modify policy locallycat dev-policy.json | jq '.directives."script-src" += ["https://new-cdn.com"]' > dev-policy.json
# 3. Validate changescspctl policy validate -f dev-policy.json
# 4. Simulate impact using cached violation dataecho "Analyzing policy impact..."CACHED_REPORTS=$(cat ~/.cspctl/cache/myapp/prod/reports.json)NEW_BLOCKS=$(echo "$CACHED_REPORTS" | jq '[.[] | select(.blocked_uri | contains("new-cdn.com"))] | length')echo "Policy would block $NEW_BLOCKS additional requests"
# 5. Generate deployment artifactscspctl header render -f dev-policy.json > headers.txtcspctl policy format -f dev-policy.json > formatted-policy.json
# 6. Create rollout plancat > rollout-plan.md << EOF## Rollout Plan- Changes: Added new-cdn.com to script-src- Estimated impact: $NEW_BLOCKS blocks- Deployment stages: 1. Deploy to staging (report-only) 2. Monitor for 24h 3. Deploy to prod at 10% traffic 4. Gradual increase to 100%EOF
echo "✅ Offline development complete. Ready to sync when online."
Step 4: Syncing After Offline Work
When connectivity returns, sync your offline changes and refresh your cache with the latest data.
# Check connectivity statuscspctl status# API: ✅ Connected# Cache: 3 days old# Pending changes: 1 policy update
# Push offline changescspctl policy push --app myapp -f dev-policy.json# ✅ Policy updated successfully
# Refresh cache with latest datacspctl cache refresh --app myapp --all-envs# Refreshing cache for all environments...# ✅ Cache updated (dev, staging, prod)
# Verify sync statuscspctl cache status# myapp/dev: Fresh (< 1 minute)# myapp/staging: Fresh (< 1 minute)# myapp/prod: Fresh (< 1 minute)
🎯 Offline Best Practices
- • Set up a cron job to refresh cache daily:
0 0 * * * cspctl cache refresh --all
- • Keep cache size under control:
du -sh ~/.cspctl/cache/
- • Archive old cache before major changes:
tar -czf cache-backup.tar.gz ~/.cspctl/cache/
- • Use
--offline
flag explicitly in scripts to avoid network attempts - • Combine with Git for version control of local policies
- • Create offline test suites using cached violation data
Keep a "break-glass" policy file locally for emergencies:
cp ~/.cspctl/cache/myapp/prod/policy.json ~/emergency-policy-backup.json
CI/CD Automation
Integrate CSPctl into your continuous integration and deployment pipelines to automatically validate, test, and deploy Content Security Policies. This ensures security policies are tested alongside your code changes and prevents unsafe policies from reaching production.
Pipeline Integration Strategy
A comprehensive CI/CD integration validates policies at multiple stages: during development, in pull requests, during staging deployment, and before production release.
🔄 Pipeline Stages
GitHub Actions Workflow
Complete GitHub Actions workflow for CSP validation, testing, and deployment with automatic rollback capabilities and comprehensive reporting.
name: CSP Pipeline
on: pull_request: paths: - 'csp.json' - 'src/**' - 'public/**' push: branches: [main, staging]
jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install CSPctl run: | curl -fsSL https://install.cspctl.com/install.sh | sh echo "$HOME/.cspctl/bin" >> $GITHUB_PATH - name: Validate Policy Syntax run: | cspctl policy validate -f csp.json echo "✅ Policy syntax valid" - name: Check for Risky Directives run: | RISKY=$(cspctl policy analyze -f csp.json --json | jq '.risky | length') if [ "$RISKY" -gt 0 ]; then echo "⚠️ Policy contains risky directives:" cspctl policy analyze -f csp.json --json | jq '.risky' exit 1 fi - name: Generate SRI Hashes run: | cspctl sri --path dist/**/*.js --algo sha384 --json > sri-hashes.json echo "Generated SRI hashes for $(jq 'length' sri-hashes.json) files" - name: Upload Artifacts uses: actions/upload-artifact@v3 with: name: csp-artifacts path: | csp.json sri-hashes.json
impact-analysis: runs-on: ubuntu-latest needs: validate if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v3 - name: Install CSPctl run: | curl -fsSL https://install.cspctl.com/install.sh | sh echo "$HOME/.cspctl/bin" >> $GITHUB_PATH - name: Configure CSPctl env: CSPCTL_API_KEY: ${{ secrets.CSPCTL_API_KEY }} run: | cspctl auth login --api-key $CSPCTL_API_KEY - name: Run Dry-Run Analysis id: dryrun run: | OUTPUT=$(cspctl rollout dry-run --app ${{ vars.APP_ID }} -f csp.json --json) echo "blocked=$(echo $OUTPUT | jq '.blocked')" >> $GITHUB_OUTPUT echo "allowed=$(echo $OUTPUT | jq '.allowed')" >> $GITHUB_OUTPUT echo "impact=$(echo $OUTPUT | jq '.impact_percentage')" >> $GITHUB_OUTPUT - name: Generate AI Suggestions run: | cspctl policy suggest --app ${{ vars.APP_ID }} --env staging --json > suggestions.json - name: Comment PR with Analysis uses: actions/github-script@v6 with: script: | const blocked = ${{ steps.dryrun.outputs.blocked }}; const allowed = ${{ steps.dryrun.outputs.allowed }}; const impact = ${{ steps.dryrun.outputs.impact }}; const comment = `## 🔒 CSP Impact Analysis ### Dry-Run Results - **Blocked Requests**: ${blocked} - **Allowed Requests**: ${allowed} - **Impact**: ${impact}% of traffic affected ### Recommendations ${blocked > 100 ? '⚠️ High impact detected. Review blocked resources carefully.' : '✅ Low impact. Safe to proceed.'} <details> <summary>View AI Suggestions</summary> \`\`\`json ${require('fs').readFileSync('suggestions.json', 'utf8')} \`\`\` </details>`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: comment });
deploy-staging: runs-on: ubuntu-latest needs: [validate, impact-analysis] if: github.ref == 'refs/heads/staging' environment: staging steps: - uses: actions/checkout@v3 - name: Deploy to Staging env: CSPCTL_API_KEY: ${{ secrets.CSPCTL_API_KEY }} run: | cspctl auth login --api-key $CSPCTL_API_KEY # Deploy in report-only mode cspctl policy push --app ${{ vars.APP_ID }} --env staging -f csp.json cspctl rollout set --app ${{ vars.APP_ID }} --env staging \ --mode report-only --traffic 100 echo "✅ Deployed to staging in report-only mode" - name: Monitor Initial Violations run: | sleep 60 # Wait for initial data cspctl reports --app ${{ vars.APP_ID }} --env staging \ --limit 100 --json > staging-violations.json VIOLATION_COUNT=$(jq 'length' staging-violations.json) echo "📊 Initial violations: $VIOLATION_COUNT"
deploy-production: runs-on: ubuntu-latest needs: validate if: github.ref == 'refs/heads/main' environment: production strategy: max-parallel: 1 steps: - uses: actions/checkout@v3 - name: Progressive Rollout env: CSPCTL_API_KEY: ${{ secrets.CSPCTL_API_KEY }} run: | cspctl auth login --api-key $CSPCTL_API_KEY # Stage 1: 10% traffic echo "🚀 Stage 1: Deploying to 10% of traffic..." cspctl policy push --app ${{ vars.APP_ID }} --env prod -f csp.json cspctl rollout set --app ${{ vars.APP_ID }} --env prod \ --mode enforce --traffic 10 # Monitor for 5 minutes sleep 300 VIOLATIONS_10=$(cspctl reports --app ${{ vars.APP_ID }} --env prod \ --limit 100 --json | jq 'length') if [ "$VIOLATIONS_10" -gt 50 ]; then echo "❌ Too many violations at 10%. Rolling back..." cspctl rollout set --app ${{ vars.APP_ID }} --env prod \ --mode report-only --traffic 100 exit 1 fi # Stage 2: 50% traffic echo "🚀 Stage 2: Expanding to 50% of traffic..." cspctl rollout set --app ${{ vars.APP_ID }} --env prod \ --mode enforce --traffic 50 sleep 300 VIOLATIONS_50=$(cspctl reports --app ${{ vars.APP_ID }} --env prod \ --limit 100 --json | jq 'length') if [ "$VIOLATIONS_50" -gt 100 ]; then echo "❌ Too many violations at 50%. Rolling back..." cspctl rollout set --app ${{ vars.APP_ID }} --env prod \ --mode enforce --traffic 10 exit 1 fi # Stage 3: 100% traffic echo "🚀 Stage 3: Full deployment..." cspctl rollout set --app ${{ vars.APP_ID }} --env prod \ --mode enforce --traffic 100 echo "✅ Successfully deployed to production"
Jenkins Pipeline
Declarative Jenkins pipeline with stages for validation, testing, and deployment with proper error handling and notifications.
pipeline { agent any environment { CSPCTL_API_KEY = credentials('cspctl-api-key') APP_ID = 'myapp' } stages { stage('Setup') { steps { sh ''' curl -fsSL https://install.cspctl.com/install.sh | sh export PATH="$HOME/.cspctl/bin:$PATH" cspctl auth login --api-key $CSPCTL_API_KEY ''' } } stage('Validate') { steps { script { def validation = sh( script: 'cspctl policy validate -f csp.json', returnStatus: true ) if (validation != 0) { error('Policy validation failed') } // Check for unsafe directives def unsafe = sh( script: "grep -E 'unsafe-inline|unsafe-eval' csp.json", returnStatus: true ) if (unsafe == 0) { unstable('Policy contains unsafe directives') } } } } stage('Impact Analysis') { when { changeRequest() } steps { script { def dryRun = sh( script: "cspctl rollout dry-run --app ${APP_ID} -f csp.json --json", returnStdout: true ).trim() def parsed = readJSON text: dryRun if (parsed.blocked > 100) { currentBuild.description = "⚠️ High impact: ${parsed.blocked} blocks" unstable('High CSP impact detected') } else { currentBuild.description = "✅ Low impact: ${parsed.blocked} blocks" } // Archive analysis writeFile file: 'dry-run-analysis.json', text: dryRun archiveArtifacts artifacts: 'dry-run-analysis.json' } } } stage('Generate SRI') { steps { sh ''' cspctl sri --path dist/**/*.js --algo sha384 --json > sri-hashes.json echo "Generated SRI hashes for:" jq -r 'keys[]' sri-hashes.json ''' archiveArtifacts artifacts: 'sri-hashes.json' } } stage('Deploy') { when { branch 'main' } steps { script { // Deploy with monitoring sh """ cspctl policy push --app ${APP_ID} --env prod -f csp.json cspctl rollout set --app ${APP_ID} --env prod \ --mode report-only --traffic 100 """ // Wait and check violations sleep(time: 5, unit: 'MINUTES') def violations = sh( script: "cspctl reports --app ${APP_ID} --env prod --json | jq 'length'", returnStdout: true ).trim().toInteger() if (violations < 50) { sh """ cspctl rollout set --app ${APP_ID} --env prod \ --mode enforce --traffic 10 """ echo "Deployed to 10% of production traffic" } else { error("Too many violations: ${violations}") } } } } } post { failure { emailext( subject: "CSP Pipeline Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}", body: "Policy deployment failed. Check violations at ${env.BUILD_URL}", to: 'security-team@example.com' ) } success { slackSend( color: 'good', message: "CSP deployed successfully to ${env.BRANCH_NAME}" ) } }}
GitLab CI Configuration
GitLab CI/CD pipeline with parallel jobs, caching, and environment-specific deployments.
.gitlab-ci.yml
variables: APP_ID: "myapp" CSPCTL_VERSION: "latest"
stages: - validate - test - deploy
before_script: - curl -fsSL https://install.cspctl.com/install.sh | sh - export PATH="$HOME/.cspctl/bin:$PATH" - cspctl auth login --api-key $CSPCTL_API_KEY
# Cache CSPctl installationcache: key: cspctl-${CSPCTL_VERSION} paths: - $HOME/.cspctl/
validate:policy: stage: validate script: - cspctl policy validate -f csp.json - | if grep -E 'unsafe-inline|unsafe-eval' csp.json; then echo "⚠️ Policy contains unsafe directives" exit 1 fi artifacts: reports: dotenv: csp-validation.env
test:dry-run: stage: test script: - | OUTPUT=$(cspctl rollout dry-run --app $APP_ID -f csp.json --json) BLOCKED=$(echo $OUTPUT | jq '.blocked') echo "CSP_BLOCKED=$BLOCKED" >> impact.env if [ "$BLOCKED" -gt 100 ]; then echo "❌ High impact: $BLOCKED blocks expected" exit 1 fi artifacts: reports: dotenv: impact.env paths: - dry-run-report.json
test:sri: stage: test parallel: matrix: - ALGO: [sha256, sha384, sha512] script: - cspctl sri --path dist/**/*.js --algo $ALGO --json > sri-$ALGO.json artifacts: paths: - sri-*.json
deploy:staging: stage: deploy environment: name: staging url: https://staging.example.com only: - staging script: - cspctl policy push --app $APP_ID --env staging -f csp.json - cspctl rollout set --app $APP_ID --env staging --mode report-only --traffic 100 - echo "✅ Deployed to staging"
deploy:production: stage: deploy environment: name: production url: https://example.com only: - main when: manual script: - | # Progressive rollout with health checks for TRAFFIC in 10 50 100; do echo "🚀 Rolling out to $TRAFFIC% of traffic..." cspctl rollout set --app $APP_ID --env prod --mode enforce --traffic $TRAFFIC sleep 300 # 5 minutes VIOLATIONS=$(cspctl reports --app $APP_ID --env prod --json | jq 'length') if [ "$VIOLATIONS" -gt $((TRAFFIC * 2)) ]; then echo "❌ Rollback triggered: $VIOLATIONS violations" cspctl rollout set --app $APP_ID --env prod --mode report-only --traffic 100 exit 1 fi done echo "✅ Full production deployment complete"
Monitoring and Alerting
Set up continuous monitoring and alerting for CSP violations in your CI/CD pipeline to catch issues early and automate responses.
#!/bin/bash# monitor-csp.sh - Continuous monitoring script
set -e
# ConfigurationTHRESHOLD_CRITICAL=100THRESHOLD_WARNING=50CHECK_INTERVAL=300 # 5 minutesSLACK_WEBHOOK=$SLACK_CSP_WEBHOOK
monitor_violations() { local env=$1 local violations=$(cspctl reports --app $APP_ID --env $env --json | jq 'length') local unique_hosts=$(cspctl reports --app $APP_ID --env $env --group-by host --json | jq 'length') echo "[$(date)] $env: $violations violations from $unique_hosts hosts" if [ "$violations" -gt "$THRESHOLD_CRITICAL" ]; then alert_critical "$env" "$violations" "$unique_hosts" elif [ "$violations" -gt "$THRESHOLD_WARNING" ]; then alert_warning "$env" "$violations" "$unique_hosts" fi # Log metrics for dashboards echo "csp.violations.$env:$violations|g" | nc -u -w0 127.0.0.1 8125 echo "csp.unique_hosts.$env:$unique_hosts|g" | nc -u -w0 127.0.0.1 8125}
alert_critical() { local env=$1 local violations=$2 local hosts=$3 # Send Slack alert curl -X POST $SLACK_WEBHOOK -H 'Content-Type: application/json' -d "{ "text": "🚨 Critical CSP Alert", "attachments": [{ "color": "danger", "fields": [ {"title": "Environment", "value": "$env", "short": true}, {"title": "Violations", "value": "$violations", "short": true}, {"title": "Unique Hosts", "value": "$hosts", "short": true}, {"title": "Action", "value": "Immediate review required", "short": true} ] }] }" # Trigger automatic rollback if in production if [ "$env" = "prod" ]; then echo "Triggering automatic rollback..." cspctl rollout set --app $APP_ID --env prod --mode report-only --traffic 100 fi}
# Main monitoring loopwhile true; do for env in staging prod; do monitor_violations $env done sleep $CHECK_INTERVALdone
🚀 CI/CD Best Practices
Require CSP validation checks to pass before merging. Set up branch protection rules that block merges if dry-run analysis shows high impact.
Implement automatic rollback triggers based on violation thresholds. If violations spike above normal levels, automatically switch to report-only mode.
Track CSP impact on page load times. Monitor if strict policies cause performance degradation due to blocked resources.
Use audit logs to track all policy changes for compliance. Generate reports showing policy evolution and security improvements over time.
Team Collaboration
Policy Review Process
- Developer creates policy changes in a feature branch
- CI validates the policy and runs dry-run analysis
- AI suggestions are generated and reviewed
- Security team reviews suggested changes
- Deploy to staging with report-only mode
- Monitor for 24-48 hours with PII-redacted reports
- Gradually roll out to production (10% → 50% → 100%)
- Audit logs track all changes for compliance
Best Practices for Teams
- Use CSPctl UI for visual policy editing and collaboration
- Enable audit logging for all production changes
- Set up alerts for high violation rates
- Use offline caching to ensure resilience
- Implement SRI hashes for all third-party resources
- Regular reviews of AI-suggested improvements
- Document rollback procedures for emergencies