CVE-2018-20676
Description
In Bootstrap before 3.4.0, XSS is possible in the tooltip data-viewport attribute.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Bootstrap before 3.4.0 allows XSS via the tooltip `data-viewport` attribute due to insufficient input sanitization.
Vulnerability
Bootstrap versions before 3.4.0 contain a cross-site scripting (XSS) vulnerability in the tooltip component. The flaw resides in how the data-viewport attribute is processed; user-supplied values are not properly sanitized before being inserted into the DOM. An attacker can inject arbitrary HTML or JavaScript through a crafted data-viewport value. This affects all Bootstrap releases prior to 3.4.0 [1] [2].
Exploitation
An attacker needs to be able to provide input that controls the tooltip's data-viewport attribute. This can be achieved if the application reflects user input into the attribute without sanitization, or if the attacker can plant malicious content (e.g., via a stored comment or post) that includes a manipulated data-viewport. No elevated privileges are required beyond the ability to inject HTML attributes. The tooltip component must be enabled and initialized on the target element [1].
Impact
Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the victim's browser. This can lead to session theft, page defacement, redirection to malicious sites, or other client-side attacks that compromise confidentiality and integrity [1].
Mitigation
The vulnerability is fixed in Bootstrap 3.4.0, released on December 18, 2018 [2]. Users should upgrade to version 3.4.0 or later. No workarounds are provided for unpatched versions. Red Hat issued RHBA-2019:1076 to address the issue in affected products [1].
AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
bootstrapnpm | < 3.4.0 | 3.4.0 |
bootstrap-sassnpm | < 3.4.0 | 3.4.0 |
twbs/bootstrapPackagist | < 3.4.0 | 3.4.0 |
org.webjars:bootstrapMaven | < 3.4.0 | 3.4.0 |
bootstrapRubyGems | < 3.4.0 | 3.4.0 |
bootstrap-sassRubyGems | < 3.4.0 | 3.4.0 |
bootstrapNuGet | < 3.4.0 | 3.4.0 |
Affected products
49- osv-coords48 versionspkg:apk/chainguard/grafana-10.4pkg:apk/chainguard/grafana-10.4-oci-compatpkg:apk/chainguard/grafana-11.2pkg:apk/chainguard/grafana-11.2-oci-compatpkg:apk/chainguard/grafana-11.3pkg:apk/chainguard/grafana-11.3-oci-compatpkg:apk/chainguard/grafana-11.4pkg:apk/chainguard/grafana-11.4-oci-compatpkg:apk/chainguard/grafana-11.5pkg:apk/chainguard/grafana-11.5-oci-compatpkg:apk/chainguard/grafana-11.6pkg:apk/chainguard/grafana-11.6-oci-compatpkg:apk/chainguard/grafana-fips-11.2pkg:apk/chainguard/grafana-fips-11.2-oci-compatpkg:apk/chainguard/grafana-fips-11.3pkg:apk/chainguard/grafana-fips-11.3-oci-compatpkg:apk/chainguard/grafana-fips-11.4pkg:apk/chainguard/grafana-fips-11.4-oci-compatpkg:apk/chainguard/grafana-fips-11.5pkg:apk/chainguard/grafana-fips-11.5-oci-compatpkg:apk/chainguard/grafana-fips-11.6pkg:apk/chainguard/grafana-fips-11.6-oci-compatpkg:apk/wolfi/grafana-10.4pkg:apk/wolfi/grafana-11.2pkg:apk/wolfi/grafana-11.2-oci-compatpkg:apk/wolfi/grafana-11.3pkg:apk/wolfi/grafana-11.3-oci-compatpkg:apk/wolfi/grafana-11.4pkg:apk/wolfi/grafana-11.4-oci-compatpkg:apk/wolfi/grafana-11.5pkg:apk/wolfi/grafana-11.5-oci-compatpkg:apk/wolfi/grafana-11.6pkg:apk/wolfi/grafana-11.6-oci-compatpkg:composer/twbs/bootstrappkg:gem/bootstrappkg:gem/bootstrap-sasspkg:maven/org.webjars/bootstrappkg:npm/bootstrappkg:npm/bootstrap-sasspkg:nuget/bootstrappkg:rpm/almalinux/custodiapkg:rpm/almalinux/python3-custodiapkg:rpm/almalinux/python3-jwcryptopkg:rpm/almalinux/python3-kdcproxypkg:rpm/almalinux/python3-pyusbpkg:rpm/almalinux/python3-qrcodepkg:rpm/almalinux/python3-qrcode-corepkg:rpm/almalinux/python3-yubico
< 10.4.19.01-r4+ 47 more
- (no CPE)range: < 10.4.19.01-r4
- (no CPE)range: < 10.4.19.01-r4
- (no CPE)range: < 11.2.10.01-r7
- (no CPE)range: < 11.2.10.01-r7
- (no CPE)range: < 11.3.9-r5
- (no CPE)range: < 11.3.9-r5
- (no CPE)range: < 11.4.8-r2
- (no CPE)range: < 11.4.8-r2
- (no CPE)range: < 11.5.10-r0
- (no CPE)range: < 11.5.10-r0
- (no CPE)range: < 11.6.7-r0
- (no CPE)range: < 11.6.7-r0
- (no CPE)range: < 11.2.10.01-r6
- (no CPE)range: < 11.2.10.01-r6
- (no CPE)range: < 11.3.9-r4
- (no CPE)range: < 11.3.9-r4
- (no CPE)range: < 11.4.8-r2
- (no CPE)range: < 11.4.8-r2
- (no CPE)range: < 11.5.10-r0
- (no CPE)range: < 11.5.10-r0
- (no CPE)range: < 11.6.7-r0
- (no CPE)range: < 11.6.7-r0
- (no CPE)range: < 10.4.19.01-r4
- (no CPE)range: < 11.2.10.01-r7
- (no CPE)range: < 11.2.10.01-r7
- (no CPE)range: < 11.3.9-r5
- (no CPE)range: < 11.3.9-r5
- (no CPE)range: < 11.4.8-r2
- (no CPE)range: < 11.4.8-r2
- (no CPE)range: < 11.5.10-r0
- (no CPE)range: < 11.5.10-r0
- (no CPE)range: < 11.6.7-r0
- (no CPE)range: < 11.6.7-r0
- (no CPE)range: < 3.4.0
- (no CPE)range: < 3.4.0
- (no CPE)range: < 3.4.0
- (no CPE)range: < 3.4.0
- (no CPE)range: < 3.4.0
- (no CPE)range: < 3.4.0
- (no CPE)range: < 3.4.0
- (no CPE)range: < 0.6.0-3.module_el8.6.0+2881+2f24dc92
- (no CPE)range: < 0.6.0-3.module_el8.6.0+2881+2f24dc92
- (no CPE)range: < 0.5.0-1.module_el8.5.0+2641+983b221b
- (no CPE)range: < 0.4-5.module_el8.6.0+2881+2f24dc92
- (no CPE)range: < 1.0.0-9.module_el8.5.0+2641+983b221b
- (no CPE)range: < 5.1-12.module_el8.6.0+2881+2f24dc92
- (no CPE)range: < 5.1-12.module_el8.6.0+2737+7e73ea90
- (no CPE)range: < 1.3.2-9.module_el8.5.0+2641+983b221b
Patches
12a5ba23ce8f0Fix/xss issues on data attributes (#27047)
6 files changed · +49 −4
js/affix.js+3 −1 modified@@ -16,7 +16,9 @@ var Affix = function (element, options) { this.options = $.extend({}, Affix.DEFAULTS, options) - this.$target = $(this.options.target) + var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target) + + this.$target = target .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
js/collapse.js+1 −1 modified@@ -137,7 +137,7 @@ } Collapse.prototype.getParent = function () { - return $(this.options.parent) + return $(document).find(this.options.parent) .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') .each($.proxy(function (i, element) { var $element = $(element)
js/tests/unit/affix.js+15 −0 modified@@ -104,4 +104,19 @@ $(function () { }, 250) }, 250) }) + + QUnit.test('should raise exception to avoid xss on target', function (assert) { + assert.expect(1) + assert.throws(function () { + + var templateHTML = '<div id="affixTarget"></div>' + $(templateHTML).appendTo(document.body) + + $('#affixTarget').bootstrapAffix({ + target: '<img src=1 onerror=\'alert(0)\'>' + }) + + }, new Error('Syntax error, unrecognized expression: <img src=1 onerror=\'alert(0)\'>')) + }) + })
js/tests/unit/collapse.js+10 −0 modified@@ -440,4 +440,14 @@ $(function () { .bootstrapCollapse('show') }) + QUnit.test('should raise exception to avoid xss on data-parent', function (assert) { + assert.expect(1) + assert.throws(function () { + $('<a role="button" data-toggle="collapse" data-parent="<img src=1 onerror=\'alert(0)\'>" href="#collapseThree">') + .appendTo('#qunit-fixture') + .bootstrapCollapse('show') + .trigger('click'); + }, new Error('Syntax error, unrecognized expression: <img src=1 onerror=\'alert(0)\'>')) + }) + })
js/tests/unit/tooltip.js+18 −0 modified@@ -1322,4 +1322,22 @@ $(function () { }) }) + QUnit.test('should raise exception to avoid xss on data-container', function (assert) { + assert.expect(1) + assert.throws(function () { + $('<button data-toggle="tooltip" data-container="<img src=1 onerror=\'alert(0)\'>" title="Tooltip on right">Tooltip on right</button>') + .appendTo('#qunit-fixture') + .bootstrapTooltip('show') + }, new Error('Syntax error, unrecognized expression: <img src=1 onerror=\'alert(0)\'>')) + }) + + QUnit.test('should raise exception to avoid xss on data-viewport', function (assert) { + assert.expect(1) + assert.throws(function () { + $('<button data-toggle="tooltip" data-viewport="<img src=1 onerror=\'alert(0)\'>" title="Tooltip on right">Tooltip on right</button>') + .appendTo('#qunit-fixture') + .bootstrapTooltip('show') + }, new Error('Syntax error, unrecognized expression: <img src=1 onerror=\'alert(0)\'>')) + }) + })
js/tooltip.js+2 −2 modified@@ -51,7 +51,7 @@ this.type = type this.$element = $(element) this.options = this.getOptions(options) - this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) + this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) this.inState = { click: false, hover: false, focus: false } if (this.$element[0] instanceof document.constructor && !this.options.selector) { @@ -204,7 +204,7 @@ .addClass(placement) .data('bs.' + this.type, this) - this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) + this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) this.$element.trigger('inserted.bs.' + this.type) var pos = this.getPosition()
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
20- access.redhat.com/errata/RHBA-2019:1076ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHBA-2019:1570ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHSA-2019:1456ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHSA-2019:3023ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHSA-2020:0132ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHSA-2020:0133ghsavendor-advisoryx_refsource_REDHATWEB
- github.com/advisories/GHSA-3mgp-fx93-9xv5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2018-20676ghsaADVISORY
- blog.getbootstrap.com/2018/12/13/bootstrap-3-4-0ghsaWEB
- blog.getbootstrap.com/2018/12/13/bootstrap-3-4-0/mitrex_refsource_MISC
- github.com/rubysec/ruby-advisory-db/blob/master/gems/bootstrap-sass/CVE-2018-20676.ymlghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/bootstrap/CVE-2018-20676.ymlghsaWEB
- github.com/twbs/bootstrap/commit/2a5ba23ce8f041f3548317acc992ed8a736b609dghsaWEB
- github.com/twbs/bootstrap/issues/27044ghsax_refsource_MISCWEB
- github.com/twbs/bootstrap/issues/27915ghsax_refsource_MISCWEB
- github.com/twbs/bootstrap/issues/27915ghsax_refsource_MISCWEB
- github.com/twbs/bootstrap/pull/27047ghsax_refsource_MISCWEB
- lists.apache.org/thread.html/rd0e44e8ef71eeaaa3cf3d1b8b41eb25894372e2995ec908ce7624d26%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/rd0e44e8ef71eeaaa3cf3d1b8b41eb25894372e2995ec908ce7624d26@%3Ccommits.pulsar.apache.org%3EghsaWEB
- www.tenable.com/security/tns-2021-14mitrex_refsource_CONFIRM
News mentions
0No linked articles in our index yet.