How CSP Restricts Unauthorized JavaScript
A Content Security Policy (CSP) restricts unauthorized JavaScript
execution by providing an HTTP response header that defines an explicit
allowlist of trusted script sources and execution rules. By default, a
robust CSP disables the execution of inline scripts, blocks dynamic code
evaluation like eval(), and restricts script loading
strictly to verified domains, cryptographic nonces, or secure hashes.
This mechanism serves as a primary defense-in-depth layer to mitigate
Cross-Site Scripting (XSS) and unauthorized code injection attacks.
Defining Trusted Script Sources
Browsers enforce CSP rules defined via the
Content-Security-Policy HTTP header. The primary directive
for controlling JavaScript execution is script-src. When a
browser receives this header, it ignores any JavaScript file originating
from an origin not explicitly specified in the policy.
For example:
Content-Security-Policy: script-src 'self' https://trustedscripts.example.com;
Under this policy, the browser will only execute scripts served from
its own domain ('self') or from
https://trustedscripts.example.com. Any script injected
from an unauthorized third-party server is immediately blocked.
Blocking Inline Scripts and Event Handlers
Attackers commonly exploit XSS vulnerabilities by injecting inline
<script> tags or HTML event handlers (such as
onload or onclick). A standard CSP inherently
distrusts all inline scripts unless explicitly instructed otherwise.
- Inline
<script>Tags: The browser refuses to run scripts written directly inside HTML pages. - Inline Event Attributes: Attributes like
<button onclick="doSomething()">are ignored and blocked. javascript:URIs: Links containing JavaScript execution protocols (e.g.,<a href="javascript:...">) are neutralized.
Preventing Dynamic Code Evaluation
JavaScript functions that convert strings to executable code
represent a severe security risk. CSP blocks these dynamic evaluation
mechanisms by default. Functions and constructs restricted include: *
eval() * Function() constructor *
setTimeout() or setInterval() when passed
string arguments instead of function references *
window.setImmediate() with string inputs
To allow these functions, developers must explicitly supply the
'unsafe-eval' keyword, though doing so weakens the policy
significantly.
Using Nonces and Hashes for Granular Control
When inline scripts are necessary, CSP allows execution without opening broad security holes through cryptographic nonces and hashes:
- Cryptographic Nonces: A server generates a unique,
cryptographically random string (a nonce) per request and attaches it to
the CSP header (e.g.,
script-src 'nonce-randomValue123'). Only inline scripts containing a matchingnonceattribute (<script nonce="randomValue123">) will execute. Attackers cannot guess this per-request token. - Cryptographic Hashes: Developers can define the
SHA-256, SHA-384, or SHA-512 hash of a trusted inline script directly in
the header (e.g.,
script-src 'sha256-...'). The browser calculates the hash of each inline script before execution; if the hash does not match the header, execution is aborted.
Policy Enforcement and Violation Reporting
When the browser encounters unauthorized JavaScript, it terminates
execution and logs a violation error in the developer console.
Additionally, administrators can monitor attempted breaches using the
report-to or report-uri directives, which
instruct the browser to send JSON payloads describing policy violations
to a designated endpoint. This ensures unauthorized execution attempts
are not only blocked in real time but also monitored continuously.