How Firefox Enforces CSP Headers to Prevent XSS Attacks

This article provides a complete overview of how the Mozilla Firefox web browser enforces Content Security Policy (CSP) headers to stop Cross-Site Scripting (XSS) attacks. By intercepting HTTP responses from web servers, parsing security directives, and strictly controlling where scripts can be loaded from and executed, Firefox neutralizes malicious code injections before they can harm the user. The following sections break down the exact mechanisms Firefox uses—from header reception and directive parsing to script blocking and violation reporting—to secure web applications.

Header Interception and Parsing

When a user navigates to a webpage, the web server responds with HTTP headers before sending the HTML content. If the server includes the Content-Security-Policy header, Firefox’s rendering engine, Gecko, intercepts it immediately.

Before parsing the HTML document, Gecko reads the CSP string and breaks it down into individual directives (such as default-src, script-src, and object-src). Firefox then compiles these rules into an active security policy object and attaches it to the document's security context, known internally as the document principal. This ensures that the rules are in place before a single line of HTML or JavaScript is processed.

Blocking Unauthorized External Scripts

Attackers often attempt to execute XSS by injecting a <script> tag that loads malicious JavaScript from an external, attacker-controlled server. Firefox prevents this by policing all outbound network requests made by the webpage.

When the HTML parser encounters a script tag with a src attribute, Firefox does not immediately fetch the file. Instead, the browser's internal content policy mechanism intercepts the request and compares the target URL against the allowlist defined in the CSP's script-src directive (or default-src if script-src is not present). If the domain does not match the approved list of sources, Firefox aborts the network request at the browser level, preventing the malicious file from ever downloading.

Neutralizing Inline Scripts

The most common vector for XSS is the injection of inline scripts directly into the HTML document. Whenever a CSP header with a script-src or default-src directive is present, Firefox automatically activates its primary XSS defense: it blocks all inline JavaScript execution by default unless explicitly permitted by the policy.

Firefox enforces this by instructing its HTML parser and its JavaScript engine, SpiderMonkey, to ignore code in the following locations:

  • Code written directly inside <script>...</script> tags.
  • Inline HTML event handlers, such as onload, onerror, and onclick.
  • Scripts executed via javascript: URLs inside anchor tags or form actions.

If an attacker manages to inject <script>stealCookies()</script> into a webpage's HTML, Firefox will parse the tag into the Document Object Model (DOM), but it will refuse to pass the code inside the tag to SpiderMonkey for execution.

Validating Nonces and Hashes

Because modern web applications often require legitimate inline scripts to function, CSP allows servers to authorize specific inline code using cryptographic nonces (numbers used once) or hashes. Firefox enforces these exceptions strictly:

  • Nonces: The server generates a random string for every page load and includes it in both the CSP header (e.g., script-src 'nonce-rAnd0m') and the HTML script tag (<script nonce="rAnd0m">). When Firefox encounters an inline script, it compares the tag's nonce attribute to the header's nonce directive. Execution is only allowed if they match character for character.
  • Hashes: The server calculates a cryptographic hash (using SHA-256, SHA-384, or SHA-512) of the legitimate script's exact text and puts it in the CSP header. When Firefox parses an inline script, it hashes the contents of the script tag in real-time. If the calculated hash matches the hash in the CSP header, the script runs. If an attacker alters even a single character of the script, the hashes will not match, and Firefox will block execution.

Restricting Dynamic Code Evaluation

XSS attacks can also occur when legitimate JavaScript already on the page is tricked into converting untrusted text strings into executable code. When a CSP header is active, Firefox instructs the SpiderMonkey engine to disable all APIs that evaluate strings as code.

Unless the server explicitly weakens its policy by including the 'unsafe-eval' keyword, Firefox will throw a security exception and halt execution whenever a script attempts to use:

  • The eval() function.
  • The Function() constructor.
  • The setTimeout() or setInterval() functions when passed a string instead of a function reference.

Violation Logging and Reporting

When Firefox blocks a resource load or script execution due to a CSP rule, it silently neutralizes the threat for the user while actively alerting the developer.

First, Firefox dispatches a SecurityPolicyViolationEvent on the document and logs a detailed error message in the browser's Web Developer Console, specifying the exact directive that was violated and the line of code responsible.

Second, if the server configured a reporting endpoint using the report-uri or report-to directive, Firefox generates a JSON report containing metadata about the violation (such as the blocked URI, the violated directive, and the page URL). The browser then sends this JSON payload asynchronously via an HTTP POST request to the server's specified endpoint, allowing website administrators to monitor and patch potential XSS vulnerabilities in real-time.