Content Security Policy for Third-Party Scripts: From Report-Only to Enforcement
By CellWall Security Research | Published September 17, 2026 | Client-Side Security | 14 min read


On this page
- What CSP Can—and Cannot—Do
- The Directives That Matter Most
- Inventory Before You Write the Policy
- Allowlist CSP vs. Strict CSP
- A Practical Report-Only Starting Point
- Nonce-Based Strict CSP
- Hash-Based CSP for Static Pages
- Move From Report-Only to Enforcement in Eight Steps
- How to Triage CSP Violation Reports
- Third-Party Script Decision Guide
- Common CSP Mistakes
- Pre-Enforcement Checklist
- Where CSP and SiteWall Fit Together
- Frequently Asked Questions
- A Policy Is a Maintained Boundary
Reading Progress
0%
14 min left
Content Security Policy (CSP) is a browser-enforced set of rules delivered in an HTTP response header. For third-party JavaScript, CSP can restrict which scripts execute, where browser connections go, where forms submit, and which pages may frame your site. A safe rollout inventories current behavior, starts in Report-Only, removes unsafe patterns, tests representative journeys, and enforces progressively.
CSP is powerful because enforcement happens where client-side code runs: in the browser. It can make injected scripts, unauthorized origins, unsafe inline handlers, and unexpected connections harder to use. It can also break checkout, authentication, analytics, support, and consent flows when deployed from an incomplete picture of the site.
This guide treats CSP as an operating process rather than a header copied from a generator. The goal is a policy that protects real users, preserves required third-party functionality, and stays aligned as the browser supply chain changes.
What CSP Can—and Cannot—Do
| CSP can help | CSP does not prove |
|---|---|
Restrict the origins or trusted script entry points from which JavaScript may execute | That code from an allowed origin is safe, necessary, or unchanged |
Reject many inline scripts, event handlers, | That the application contains no XSS or unsafe DOM data flow |
Limit fetch, XHR, WebSocket, beacon, and other connections with | That every permitted destination receives appropriate data |
Restrict form destinations and framing relationships | That business logic, authorization, and user intent are correct |
Generate violation telemetry before or during enforcement | That every report is an attack or that unreported behavior is safe |
CSP can reduce exploitability, but it is not a substitute for safe DOM APIs, contextual output encoding, sanitization, dependency management, script inventory, integrity controls, runtime visibility, or incident response. An allowed third-party script generally retains the page privileges the browser gives it.
The Directives That Matter Most
| Directive | What it governs | Third-party security question |
|---|---|---|
| JavaScript sources and execution rules | Which scripts or trusted entry points may execute? |
| Script elements and script blocks | Do script elements need a narrower policy than the general script fallback? |
| Inline event handlers | Can handlers such as |
| Fetch, XHR, WebSocket, EventSource, and beacon destinations | Where may page code transmit or retrieve data? |
| Frames the protected page may load | Which embedded providers are required? |
| Who may embed the protected page | Should another origin be allowed to frame this page? |
| Where forms may submit | Could an injected or modified form send sensitive data elsewhere? |
| Plugin-based embedded content | Can legacy object execution be disabled with |
| Permitted targets for the document's | Can an injected base URL rewrite relative script or link destinations? |
| Fallback for many fetch directives that are not explicitly set | Which resource types still inherit a broad default? |
| Violation report destinations | Where are reports collected, normalized, and reviewed? |
Directives such as frame-ancestors, form-action, and base-uri need their own decisions. Do not assume default-src 'none' automatically provides every navigation, framing, and document restriction you intend.
Inventory Before You Write the Policy
A policy based only on page source or a tag-manager export will miss conditional resources and nested dependencies. Begin with a third-party JavaScript inventory built from representative browser sessions, then connect each observed resource and destination to an owner, purpose, loading chain, approved scope, and removal path.
Observe representative states
Critical journeys such as authentication, account recovery, checkout, payment, and support.
Anonymous and authenticated sessions, consent choices, locales, devices, experiments, and error paths.
Scripts introduced by application bundles, tag managers, consent tools, frames, widgets, and loaders.
Network destinations used for APIs, telemetry, media, fraud services, and vendor dependencies.
Decide before allowing
Confirm the internal owner and specific purpose of each integration.
Record where the script is approved to run and which destinations it requires.
Remove obsolete resources and narrow wildcard or shared-host dependencies where practical.
Identify code patterns that require refactoring: inline handlers,
eval(), injected script URLs, or broad dynamic loaders.
Allowlist CSP vs. Strict CSP
| Approach | Trust decision | Strength | Operational tradeoff |
|---|---|---|---|
Host allowlist | Trust scripts from named origins | Can block unlisted origins and is often easier to introduce | Large or shared origins can authorize more code than intended; vendor domain changes expand maintenance |
Nonce-based strict CSP | Trust script elements carrying a fresh unpredictable response-specific nonce | Avoids relying primarily on long host lists and works well with dynamic server-rendered HTML | Requires per-response nonce generation and deliberate propagation to trusted script elements |
Hash-based strict CSP | Trust specific inline or external script bytes represented by hashes | Fits static HTML and binds trust to content | Every content change requires a new hash; dynamic scripts can be difficult |
Strict CSP with | Allow a nonce- or hash-trusted script to load further scripts | Can support legitimate loaders without enumerating every descendant origin | Delegates trust down the loading chain; unsafe loader behavior remains dangerous |
A strict CSP is the preferred target for mitigating script injection when the architecture can support it. A carefully scoped allowlist can still provide value, especially during migration, but adding domains until reports disappear often produces a policy that looks complete while permitting broad execution paths.
A Practical Report-Only Starting Point
Report-Only evaluates a proposed policy without blocking violations. It is useful for discovering incompatibilities and testing a future policy, but it does not protect users until an enforcing Content-Security-Policy header is also active.
Reporting-Endpoints: csp-endpoint="https://reports.example.com/csp"
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self';
connect-src 'self' https://api.example.com;
img-src 'self' data:;
style-src 'self';
font-src 'self';
frame-src 'none';
object-src 'none';
base-uri 'none';
form-action 'self';
frame-ancestors 'none';
report-to csp-endpoint;
report-uri https://reports.example.com/cspReplace the example origins and directives with decisions based on your application. A policy copied without representative testing may miss required resources, authorize unnecessary ones, or create a false sense of protection.
Nonce-Based Strict CSP
For dynamically rendered HTML, generate an unpredictable nonce for every response. Put the same value in the response's script-src directive and only on script elements the application deliberately trusts.
Content-Security-Policy:
script-src 'nonce-{FRESH_RANDOM_VALUE}' 'strict-dynamic';
object-src 'none';
base-uri 'none';
form-action 'self';
frame-ancestors 'none'<script nonce="{FRESH_RANDOM_VALUE}" src="/app.js"></script>
<script nonce="{FRESH_RANDOM_VALUE}" src="https://vendor.example/widget.js"></script>The nonce must be unpredictable and different for every HTTP response. Do not use middleware that adds the nonce to every script tag after rendering: an attacker-injected script could receive the same trust token. Apply it through a trusted rendering path.
Hash-Based CSP for Static Pages
Static HTML cannot generate a fresh nonce per response. A hash-based policy can authorize exact script content instead. Recalculate the CSP hash whenever the authorized script bytes change—even whitespace changes the result.
Content-Security-Policy:
script-src 'sha256-{BASE64_HASH}' 'strict-dynamic';
object-src 'none';
base-uri 'none'CSP hashes and Subresource Integrity are related but distinct. CSP decides whether code may execute under the page's policy. SRI verifies that an eligible fetched resource matches expected bytes. For external scripts, browser requirements and markup details differ, so test the combination rather than treating one hash as an interchangeable control everywhere.
Move From Report-Only to Enforcement in Eight Steps
Define the protection goal
Decide whether the first milestone targets script injection, exfiltration destinations, framing, form submissions, or a broader strict policy. Name the journeys and owners in scope.
Build the observed baseline
Inventory scripts, initiators, frames, connections, and conditional states from representative browser sessions.
Choose the policy architecture
Prefer nonce- or hash-based strict CSP where feasible. Document any temporary host allowlist and why it is necessary.
Deploy Report-Only
Send the proposed policy as an HTTP response header and collect reports at a controlled endpoint without blocking users.
Classify violations
Separate required application behavior, obsolete integrations, policy gaps, extensions or environmental noise, and suspicious activity.
Refactor and narrow
Remove inline handlers and unsafe code patterns, minimize third parties, constrain destinations, and avoid broad wildcard exceptions.
Enforce progressively
Start with low-risk routes or a traffic cohort, keep a tested rollback path, and verify business and security telemetry before expanding.
Operate the policy
Review policy changes like code, test releases and vendor changes, monitor violations and runtime behavior, and retire exceptions that no longer have an owner.
How to Triage CSP Violation Reports
| Signal | Likely explanation | Next action |
|---|---|---|
Known resource on an expected journey | Policy is missing a genuinely required behavior | Confirm owner and purpose, then add the narrowest justified rule or refactor |
Known resource on an unexpected page | Scope drift, shared template, tag trigger, or routing behavior | Trace the initiator and correct the loading scope before broadening CSP |
Unknown script or destination | Undocumented integration, injected code, compromised dependency, or browser environment noise | Preserve context, correlate across sessions, identify the initiator, and investigate |
Inline-script violation | Inline code, event handler, framework behavior, or injection attempt | Use source location and sample carefully; refactor legitimate code to nonces, hashes, or external handlers |
Sudden report spike after release | Application or policy deployment changed | Correlate with the release, reproduce critical journeys, and roll back or repair deliberately |
Reports isolated to unusual clients | Extension, malware, proxy, automation, or a narrow user state | Cluster by user agent and context; do not globally allow the source just to suppress noise |
A blocked URI alone is not enough context. Preserve the effective directive, disposition, document route, source location when available, release version, session conditions, and the resource's initiator chain. Prioritize repeated signals on sensitive journeys over isolated extension noise.
Validate request methods and content types, authenticate ingestion where practical, apply rate limits, minimize retained fields, and avoid reflecting report values into an unsafe dashboard. CSP telemetry can contain URLs and other context that should follow your data-handling rules.
Third-Party Script Decision Guide
| Third-party pattern | Preferred treatment | Residual risk |
|---|---|---|
Static versioned library | Pin the version, use SRI where compatible, and authorize through a nonce, hash, or narrow source rule | Approved bytes may still contain vulnerabilities or unsafe behavior |
Dynamic vendor script at a stable URL | Limit page scope and destinations, document the provider, and monitor content and behavior changes | CSP cannot distinguish a legitimate update from malicious code served by the same allowed source |
Tag manager | Restrict publishing access, govern tags and triggers, nonce the trusted loader where appropriate, and observe descendants | With |
Embedded widget | Follow iframe security best practices: prefer a cross-origin sandboxed frame, narrow Permissions Policy, and validated messaging | Frame permissions and |
Script requiring | Challenge the requirement, upgrade or replace the dependency, and isolate it when removal is not immediate |
|
Broad shared CDN | Prefer a dedicated path, self-hosted reviewed artifact, hash, or narrower provider endpoint | Origin-level allowlisting may authorize unrelated attacker-controlled content on the same service |
Common CSP Mistakes
Policies that look safer than they are
Adding
*, broad schemes, shared cloud origins, or large wildcard domains until reports stop.Using
'unsafe-inline'or'unsafe-eval'as permanent compatibility switches.Assuming
'self'means the delivered code is trusted, immutable, or free from upload and JSONP-style execution paths.Using CSP as the only defense against XSS or third-party compromise.
Rollouts that create operational risk
Enforcing from a homepage-only scan without testing authenticated and transactional journeys.
Copying a generic policy without assigning owners to exceptions and breakage decisions.
Automatically allowlisting every reported source, including browser-extension or malware noise.
Deploying once and never comparing the policy with releases, tag changes, and runtime drift.
Pre-Enforcement Checklist
Security readiness
The policy has an explicit goal and avoids unjustified wildcards and unsafe keywords.
Nonce values are unpredictable, response-specific, and applied only by trusted rendering code—or hashes are generated from controlled content.
object-src,base-uri,form-action,frame-ancestors, and connection destinations have deliberate values.Every third-party exception maps to an inventory record, owner, purpose, and approved scope.
Operational readiness
Representative journeys pass in supported browsers, including consent, payment, login, error, and regional variants.
Violation collection is rate-limited, privacy-reviewed, normalized, and connected to an accountable response process.
Application releases, tag-manager publishing, and vendor changes trigger policy validation.
The rollout has measurable success criteria, a staged expansion plan, and a tested rollback path.
Test the response header the browser actually receives—not only the framework configuration. CDNs, reverse proxies, middleware, redirects, error pages, and cached HTML can produce a different policy or omit it entirely.
Where CSP and SiteWall Fit Together
CSP expresses browser-enforced rules. SiteWall can support the surrounding operating process by helping teams observe resources, providers, loading relationships, destinations, sensitive browser behavior, and changes across captured sessions. That context can make policy design and violation investigation more informed.
The controls are complementary. CSP can block behavior that violates the active policy; third-party JavaScript monitoring can help reveal changes within permitted relationships and browser states. The CSP vs. SRI vs. monitoring comparison maps each layer to the failures it prevents, detects, and misses. Your team remains responsible for policy design, coverage, authorization, testing, incident handling, and decisions about acceptable behavior.
Build CSP From What Browsers Actually Run
Evaluate SiteWall on representative journeys to see how resource discovery, loading relationships, destinations, browser behavior, and change context can support CSP design and ongoing third-party governance.
Frequently Asked Questions
What is Content Security Policy?
Content Security Policy is a browser security mechanism configured mainly through HTTP response headers. It lets a site restrict resource loading and behaviors such as script execution, network connections, form submissions, and framing.
Should CSP start in Report-Only mode?
For an existing application, Report-Only is usually the safest way to evaluate a proposed policy without blocking users. It still requires representative testing and triage, and it provides no blocking protection until an enforcing policy is deployed.
What is the difference between CSP Report-Only and enforcement?
A Content-Security-Policy-Report-Only header monitors violations and can send reports but does not block them. A Content-Security-Policy header enforces its rules. Both can be active simultaneously to enforce one policy while evaluating a stricter future policy.
Are CSP nonces reusable?
No. A nonce should be unpredictable and newly generated for every HTTP response. The server places that response-specific value in the CSP header and only on script or style elements it deliberately trusts.
Does `strict-dynamic` make third-party scripts safe?
No. It lets a nonce- or hash-trusted script pass execution trust to scripts it creates. This can simplify policies for loaders, but it also makes the trusted loader and its script-creation behavior security-critical.
Can CSP stop a compromised allowed third party?
Not necessarily. If malicious code is delivered through a source or trust path your policy allows, CSP may permit it. Layer CSP with SRI where appropriate, inventory, supplier controls, behavior monitoring, data-flow restrictions, and incident response.
Can CSP be delivered in a meta tag?
An enforcing policy can be placed in a meta element, but it must appear early and does not support the full header feature set. Report-Only, frame-ancestors, reporting directives, and some other capabilities require an HTTP response header. Header delivery is preferred.
How often should a CSP be reviewed?
Review it whenever application code, tags, vendors, routes, or browser integrations change, and on a scheduled cadence based on risk. Policy exceptions should have owners and should expire or be revalidated rather than accumulating indefinitely.
A Policy Is a Maintained Boundary
The most effective CSP is not the longest or the strictest-looking header. It is the narrowest policy your architecture can support, backed by a verified inventory, safe code patterns, representative testing, useful reporting, accountable exceptions, and a controlled path from observation to enforcement.
Start with one critical journey. Observe it, write the intended boundary, run that boundary in Report-Only, resolve violations deliberately, and enforce it for a limited cohort or route. Once the feedback loop works, expand coverage without turning every new report into permanent trust.
Authoritative Sources and Related Guides
Continue exploring
Read the practical guides that clarify the surrounding risks, controls, and evidence.
Explore the client-side security hub
Client-Side Security
How to Build a Third-Party JavaScript Inventory: A Practical Template
Build a living third-party JavaScript inventory that connects every observed script to its provider, owner, purpose, loading chain, browser access, destinations, approval, and review status.

Supply Chain Security
OWASP Subresource Integrity (SRI) Guide: Securing the Supply Chain
An authoritative primer on implementing Subresource Integrity (SRI) to prevent third-party script injection, Magecart attacks, and unauthorized CDN modifications.

Client-Side Security
Third-Party JavaScript Monitoring: Uptime, Updates, and Behavioral Drift
Learn how to monitor third-party script availability, performance, update frequency, dependency changes, and unexpected behavior in the browser.