home/blog/bypassing-csp-real-world
Web Security

Bypassing Content-Security-Policy in the Real World

R
Muhammad Rajib Hawlader
-Jun 05, 2026-6 min read

A field guide to CSP gadgets, nonce reuse, and JSONP endpoints that quietly defeat your strongest header.

Bypassing Content-Security-Policy in the Real World
Advertisement
after intro - 728x90 desktop / fluid mobile

Content-Security-Policy is one of the best browser defenses we have, but it is also easy to weaken accidentally. Real bypasses usually come from trusted script gadgets, loose host allowlists, or a nonce that leaks into attacker-controlled markup.

Trust only what must execute

The safest policy starts small: no wildcard script sources, no broad CDN allowlists, and no inline execution unless it is backed by nonces or hashes.

strict-csp.txt
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-random-per-request';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
TIP

Treat CSP as exploit mitigation, not as input validation. You still need output encoding and sanitizer discipline.

Watch for script gadgets

Trusted scripts can become gadgets when they read attacker-controlled DOM attributes and turn them into executable behavior. A policy that trusts the script also trusts its unsafe behaviors.

Advertisement
mid article - 300x250 responsive

JSONP and legacy endpoints

Any endpoint that returns JavaScript can become a script source. If an allowlisted domain still exposes JSONP, the policy may allow attacker-selected code through the front door.

Hardening checklist

  • Remove unused hosts from script-src.
  • Rotate nonces per response.
  • Avoid unsafe-inline and unsafe-eval.
  • Audit third-party scripts for gadget behavior.
  • Report violations before enforcing a stricter policy.

Common bypass paths

Most real CSP bypasses are not magic payloads; they are policy design mistakes. A site may block inline JavaScript but allow an old analytics endpoint, a JSONP callback, or a trusted script that turns DOM attributes into dynamic code. Attackers look for anything that lets their input become executable while still satisfying the policy.

High-risk patterns:

  • Broad script-src https: allowlists.
  • Wildcard CDN rules such as *.example-cdn.com.
  • Nonces copied into rendered HTML where user content can read them.
  • Framework gadgets that evaluate templates, URLs, or data attributes.
  • base-uri missing, allowing attackers to alter relative script targets.

Defender visibility

CSP reports are noisy, but they are still useful when grouped by blocked URI, violated directive, route, and user agent. A sudden spike in script-src violations on one route may indicate an active XSS probe. Pair reports with application logs so analysts can see which user input produced the violation.

csp-report-example.json
{
  "violated-directive": "script-src-elem",
  "blocked-uri": "https://evil.example/payload.js",
  "document-uri": "https://app.example/profile"
}

Rollout strategy

Ship CSP in Report-Only mode first, but do not leave it there forever. Start strict on admin panels and authenticated flows, where script inventory is usually smaller. Move toward nonce-based scripts, remove legacy inline handlers, and document every third-party host with an owner and reason.

WARNING

A CSP that nobody owns slowly becomes a pile of exceptions. Treat every new host in script-src like a dependency with security review.

Testing methodology

Use browser dev tools, CSP evaluators, and manual payloads. Start by confirming whether inline scripts execute, then check whether trusted hosts can be abused. If a nonce exists, inspect whether it appears in places untrusted content can read. Test routes separately; CSP often differs between marketing pages, dashboards, and admin panels.

Developer workflow

Make CSP part of code review. When a feature needs a new script host, require the owner to explain why, what data the script can access, and whether a self-hosted or server-side alternative exists. Keep a small policy inventory in the repo so security decisions survive team changes.

Measuring success

A good CSP program reduces exploitable script paths without breaking product velocity. Track policy strictness, report-only violations, exception count, and third-party script ownership. The goal is not a perfect header overnight; it is continuous reduction of browser execution risk.

Policy examples to compare

A weak policy usually looks flexible because it tries to avoid breaking anything. It allows broad hosts, inline execution, and evaluation. A stronger policy is more explicit: scripts come from the application and per-response nonces, objects are disabled, framing is restricted, and base URI changes are blocked.

When reviewing a policy, ask whether an attacker with HTML injection can make the browser execute script anyway. If the answer is yes through JSONP, a script gadget, an overly broad CDN, or leaked nonce access, the policy is not providing the protection the team expects.

Maintenance ownership

CSP needs an owner because browser code changes constantly. Assign ownership to the team that controls frontend platform or application security, and require justification for every new script source. Keep reports visible in dashboards so the team can distinguish legitimate breakage from attack traffic.

The best long-term CSP programs are boring: fewer hosts over time, no legacy JSONP, predictable nonce handling, and a clear process for removing exceptions after migrations. That kind of maintenance turns CSP from a checkbox into a real browser containment layer.

Advertisement
end of article - 728x90 desktop / fluid mobile