KobReySec Logo
Published Last reviewed
Published Last reviewed
CSP, Broken Down

Content Security Policy Explained

Content Security Policy (CSP) is one of the browser's most versatile security controls. It can restrict scripts, styles, connections, framing, form destinations, embedded objects, and more.

This guide is not a CSP generator. It is designed to help you understand what an existing policy permits, how its directives interact, and where security-relevant gaps may exist.

Plain-English breakdown Directive map Tester perspective
Start With the Structure

How to Read a CSP Without Treating It Like Alphabet Soup

A policy is a series of semicolon-separated directives. Most directives are followed by one or more source expressions that define what is allowed, but not every directive takes a source expression. Some directives are standalone instructions to the browser.

Content-Security-Policy: default-src 'self'; img-src 'self' data:; object-src 'none'; upgrade-insecure-requests;
01

Directive

img-src tells the browser which image sources are allowed.

02

Source expression

'self' or data: defines where the browser may load that content from.

03

Standalone directive

upgrade-insecure-requests takes no source expression. Its presence alone instructs the browser to upgrade eligible insecure requests.

A CSP header being present does not mean the policy is strong. The useful question is what the policy actually permits and what each directive is doing.
The Core Directives

The Pieces You Will See Most Often

These directives explain most real-world CSP reviews. You do not need every directive in the specification memorized to understand what a policy is trying to do.

default-src

The fallback

Provides the baseline source list for several resource-loading directives that are not explicitly present.

script-src

JavaScript

Controls where scripts may load from and, depending on the policy, whether inline or dynamically evaluated JavaScript may execute.

style-src

Stylesheets

Controls where CSS may load from and whether inline styling is permitted.

img-src

Images

Controls permitted image sources, including hosts, schemes, and sources such as data:.

connect-src

Browser connections

Controls destinations used by fetch(), XMLHttpRequest, WebSockets, EventSource, and similar browser APIs.

font-src

Fonts

Controls where web fonts may be loaded from.

frame-src

What this page may frame

Controls which sources this application may load into frames such as <iframe>. Think: What can I frame?

frame-ancestors

Who may frame this page

Controls which parent sites may embed the current page. Think: Who can frame me? This is the framing control commonly used to defend against clickjacking.

object-src

Embedded objects

Controls plugin-style content such as <object> and <embed>. Modern applications often set this to 'none'.

base-uri

Base URL control

Restricts which URLs may be used by the document's <base> element.

form-action

Form destinations

Controls where HTML forms may submit data. This directive does not inherit from default-src.

upgrade-insecure-requests

Upgrade insecure requests

A standalone directive with no source expression. It tells the browser to upgrade eligible HTTP resource requests to HTTPS. Useful for transport hygiene, but by itself it does not restrict script sources, framing, connections, form destinations, or other content.

frame-src and frame-ancestors are related, but they are not opposites of the same directive. One controls what the current page may load in a frame; the other controls which parent pages may frame the current page.
Source Expressions

What the Directive Is Actually Allowed to Trust

The directive tells you what behavior is being controlled. The source expression tells you where that behavior is permitted. Some expressions are intentionally broad, and some can materially weaken the protection a directive would otherwise provide.

Neutral Common expression. Evaluate it in context. Review Broadens trust and deserves justification. High concern Commonly weakens an important CSP protection.

Color is a review aid, not a verdict. Green does not automatically mean safe, and amber or red still need to be interpreted in the directive and application context where the expression appears.

'self'

Allow the same origin as the protected page.

'none'

Allow nothing for that directive.

Review*

Allow a very broad set of sources. The exact effect depends on the directive, but a wildcard often expands trust far beyond what the application actually needs.

https://cdn.example.com

Allow a specific host source.

Reviewhttps:

Allow sources broadly over HTTPS rather than limiting trust to specific hosts. Encryption does not make every HTTPS origin trustworthy.

Reviewdata:

Allow data: URLs. Common and often reasonable for images, but more concerning when used with directives that can load active content.

blob:

Allow browser-generated blob URLs, often used for workers, media, or generated files. Review where it is permitted and whether the application requires it.

'nonce-...'

Allow inline content carrying a matching unpredictable, per-response nonce.

'sha256-...'

Allow specific inline content whose cryptographic hash matches the policy.

High concern'unsafe-inline'

Allows inline script or style behavior. In script-src, this can remove a major barrier CSP would otherwise place in front of injected JavaScript.

High concern'unsafe-eval'

Allows string-to-code execution mechanisms such as eval(), weakening CSP's ability to constrain dynamically generated JavaScript.

The Gotchas

Why a Valid CSP Can Still Be a Weak CSP

default-src does not cover everything

Directives such as frame-ancestors, form-action, and base-uri need their own rules when they matter.

Broad sources broaden trust

Wildcards, scheme-wide sources, and large host patterns may permit far more content than the application actually needs.

Unsafe keywords change the story

'unsafe-inline' and 'unsafe-eval' can undermine the controls that make CSP useful against script injection.

Trusted third parties become part of the model

Every CDN, analytics host, and external script source expands the set of systems the browser is being told to trust.

Content-Security-Policy: script-src * 'unsafe-inline' 'unsafe-eval'

That is technically a CSP. It is also an example of why checking for the header alone tells you very little.

Content-Security-Policy: upgrade-insecure-requests;

upgrade-insecure-requests is also a valid CSP directive, but a policy containing only that directive is not meaningfully restricting content sources. It upgrades eligible insecure requests; it does not provide the source restrictions people usually associate with CSP.

Read One With Us

Turn a Real Policy Into Plain English

default-src 'self';
script-src 'self' https://cdn.example.com;
img-src 'self' data:;
connect-src 'self' https://api.example.com;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
default-srcUse the same origin as the fallback for supported resource types.
script-srcAllow JavaScript from the application and the approved CDN.
img-srcAllow same-origin images and embedded data: images.
connect-srcAllow browser-side connections to the application and its API.
object-srcDo not allow plugin-style embedded objects.
base-uriRestrict document base URLs to the same origin.
form-actionRestrict form submissions to the same origin.
frame-ancestorsDo not allow any site to frame the application.
upgrade-insecure-requestsUpgrade eligible insecure resource requests to HTTPS. No source expression is required.
In plain English: this policy keeps most content on the application's own origin, allows JavaScript from one approved CDN, permits images embedded with data: URLs, allows browser-side connections to one API, blocks plugin-style objects, keeps base URLs and form submissions on the same origin, prevents other sites from framing the application, and upgrades eligible insecure resource requests to HTTPS.
Tester Perspective

CSP Is Defense in Depth, Not a Substitute for Fixing the Bug

A strong policy can make exploitation harder and reduce the impact of some client-side vulnerabilities, especially Cross-Site Scripting (XSS). It does not make the underlying flaw disappear.

XSS

Restrict script execution and where executable content may come from.

Clickjacking

Use frame-ancestors to control which sites may frame the application.

Learn more

Data exfiltration

Use connect-src to constrain browser-side connections to approved destinations.

Form submission

Use form-action to restrict where forms may send data.

Put It Against a Real Site

Want to See What Your CSP Actually Allows?

A Content Security Policy can look restrictive at a glance and still leave important gaps. Start by checking the headers your application currently returns.

Let's evaluate yours
Need a deeper review? KobReySec performs hands-on web application and API penetration testing that evaluates browser-side controls in the context of the actual application, rather than treating individual headers as isolated checklist items. Learn about penetration testing.