TL;DR
Bootstrap 3.3.7 is vulnerable to Cross-Site Scripting (XSS) attacks due to insufficient sanitisation of user-supplied data in its JavaScript components, particularly when using the `data-target` attribute with dynamic content. This guide explains how to mitigate this risk by properly encoding your data before injecting it into Bootstrap’s HTML attributes.
Understanding the Problem
The XSS vulnerability arises because Bootstrap’s JavaScript code doesn’t adequately escape user input used in selectors (like `data-target` for modals or tabs). If an attacker can inject malicious JavaScript code into a `data-target` value, it will be executed when the corresponding component is activated.
Solution Steps
- Identify Vulnerable Code: Look for places in your application where you are dynamically setting Bootstrap’s attributes that accept user input. Common examples include:
- Modal windows (
data-target="#myModal") - Tabs (
data-target="#tabContent") - Tooltips and Popovers (
data-target="#tooltipTarget") - Encode User Input: Before inserting user data into these attributes, encode it to prevent the browser from interpreting it as executable code. Use a suitable encoding function provided by your server-side language or framework. Here are examples for common languages:
- PHP: Use
htmlspecialchars()with the correct flags. - Python (Flask/Django): Use the
escape()function from your templating engine.from flask import escape user_input = request.args.get('user_input') data_target = 'data-target="' + escape(user_input) + '"' - JavaScript (Client-Side – Use with Caution): While client-side encoding is possible, it’s generally less secure than server-side encoding. Use a library like DOMPurify if you must encode on the client.
const userInput = document.getElementById('userInput').value; dataTarget = 'data-target="' + DOMPurify.sanitize(userInput) + '"';
- PHP: Use
- Server-Side Encoding is Crucial: Always perform encoding on the server side before sending data to the client. Client-side encoding can be bypassed.
- Validate Input (Best Practice): In addition to encoding, validate user input to ensure it conforms to expected patterns and lengths. This reduces the attack surface even further.
- Whitelist Allowed Characters: Only allow specific characters that are necessary for your application.
- Limit Length: Restrict the maximum length of user input to prevent excessively long strings.
- Update Bootstrap (If Possible): While this guide focuses on mitigating the vulnerability in version 3.3.7, consider upgrading to a newer version of Bootstrap if feasible. Newer versions often include security fixes.
- Content Security Policy (CSP): Implement a Content Security Policy (CSP) to further restrict the execution of scripts from untrusted sources. This adds an extra layer of defence against XSS attacks.
Example Scenario
Let’s say you have a modal window where the ID is dynamically set based on user input.
<button data-toggle="modal" data-target="#{{ user_supplied_id }}">Open Modal</button>
If user_supplied_id is not encoded, an attacker could inject a malicious value like " onclick="alert('XSS')". The resulting HTML would be:
<button data-toggle="modal" data-target="#" onclick="alert('XSS')">Open Modal</button>
This would execute the JavaScript code when the button is clicked.
Testing
- Try Injecting Malicious Code: Attempt to inject simple XSS payloads (e.g.,
<script>alert('XSS')</script>) into the vulnerable input fields. - Verify Encoding: Check that the injected code is properly encoded in the generated HTML source code. It should appear as text, not executable JavaScript.

