VYPR
Moderate severityOSV Advisory· Published Jan 9, 2019· Updated Aug 5, 2024

CVE-2018-20677

CVE-2018-20677

Description

In Bootstrap before 3.4.0, XSS is possible in the affix configuration target property.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Cross-site scripting (XSS) vulnerability in Bootstrap's affix plugin allows attackers to inject arbitrary JavaScript via the target property before version 3.4.0.

Vulnerability

In Bootstrap versions prior to 3.4.0, the affix plugin does not properly sanitize the target configuration property, leading to a cross-site scripting (XSS) vulnerability. An attacker can inject arbitrary HTML and JavaScript through this property. [1]

Exploitation

An attacker must be able to control the value of the target property passed to the affix plugin, typically via user input or data from an untrusted source. By providing a malicious string containing JavaScript, the attacker can execute arbitrary code in the context of the victim's browser when the affix plugin processes the target. [1]

Impact

Successful exploitation allows the attacker to execute arbitrary JavaScript in the user's browser, potentially leading to session hijacking, data theft, or defacement. The attack runs in the context of the affected web page. [1]

Mitigation

Upgrade to Bootstrap version 3.4.0 or later, which fixes the issue. Red Hat also released an advisory (RHBA-2019:1076) for affected products. [1] No workaround is documented; the only mitigation is to update.

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.

PackageAffected versionsPatched versions
bootstrapnpm
< 3.4.03.4.0
bootstrap-sassnpm
< 3.4.03.4.0
twbs/bootstrapPackagist
< 3.4.03.4.0
org.webjars:bootstrapMaven
< 3.4.03.4.0
bootstrapRubyGems
< 3.4.03.4.0
bootstrap-sassRubyGems
< 3.4.03.4.0
bootstrapNuGet
< 3.4.03.4.0

Affected products

49

Patches

1
2a5ba23ce8f0

Fix/xss issues on data attributes (#27047)

https://github.com/twbs/bootstrapdon-spykerAug 13, 2018via ghsa
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

22

News mentions

0

No linked articles in our index yet.