Package: release.debian.org
Severity: normal
Tags: stretch
User: release.debian....@packages.debian.org
Usertags: pu

Hi all,

A little fix for CVE-2019-8331.

Cheers,
Xavier

-- System Information:
Debian Release: buster/sid
  APT prefers testing
  APT policy: (900, 'testing'), (500, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.19.0-2-amd64 (SMP w/4 CPU cores)
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8), LANGUAGE= 
(charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
diff -Nru twitter-bootstrap3-3.3.7+dfsg/debian/changelog 
twitter-bootstrap3-3.3.7+dfsg/debian/changelog
--- twitter-bootstrap3-3.3.7+dfsg/debian/changelog      2019-02-04 
22:25:25.000000000 +0100
+++ twitter-bootstrap3-3.3.7+dfsg/debian/changelog      2019-02-21 
21:42:06.000000000 +0100
@@ -1,3 +1,9 @@
+twitter-bootstrap3 (3.3.7+dfsg-2+deb9u2) UNRELEASED; urgency=medium
+
+  * Add patch to fix CVE-2019-8331: XSS in tooltip or popover
+
+ -- Xavier Guimard <y...@debian.org>  Thu, 21 Feb 2019 21:42:06 +0100
+
 twitter-bootstrap3 (3.3.7+dfsg-2+deb9u1) stretch; urgency=high
 
   * Team upload.
diff -Nru twitter-bootstrap3-3.3.7+dfsg/debian/patches/CVE-2019-8331.patch 
twitter-bootstrap3-3.3.7+dfsg/debian/patches/CVE-2019-8331.patch
--- twitter-bootstrap3-3.3.7+dfsg/debian/patches/CVE-2019-8331.patch    
1970-01-01 01:00:00.000000000 +0100
+++ twitter-bootstrap3-3.3.7+dfsg/debian/patches/CVE-2019-8331.patch    
2019-02-21 21:40:12.000000000 +0100
@@ -0,0 +1,257 @@
+Description: Fix XSS - CVE-2019-8331
+Author: Xavier Guimard <y...@debian.org>
+Origin: upstream
+Forwarded: not-needed
+Last-Update: 2019-02-21
+
+--- a/js/dropdown.js
++++ b/js/dropdown.js
+@@ -29,7 +29,7 @@
+       selector = selector && /#[A-Za-z]/.test(selector) && 
selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+     }
+ 
+-    var $parent = selector && $(document).find(selector)
++    var $parent = selector !== '#' ? $(document).find(selector) : null
+ 
+     return $parent && $parent.length ? $parent : $this.parent()
+   }
+--- a/js/popover.js
++++ b/js/popover.js
+@@ -45,10 +45,25 @@
+     var title   = this.getTitle()
+     var content = this.getContent()
+ 
+-    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+-    $tip.find('.popover-content').children().detach().end()[ // we use append 
for html objects to maintain js events
+-      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 
'text'
+-    ](content)
++    if (this.options.html) {
++      var typeContent = typeof content
++
++      if (this.options.sanitize) {
++        title = this.sanitizeHtml(title)
++
++        if (typeContent === 'string') {
++          content = this.sanitizeHtml(content)
++        }
++      }
++
++      $tip.find('.popover-title').html(title)
++      $tip.find('.popover-content').children().detach().end()[
++        typeContent === 'string' ? 'html' : 'append'
++      ](content)
++    } else {
++      $tip.find('.popover-title').text(title)
++      $tip.find('.popover-content').children().detach().end().text(content)
++    }
+ 
+     $tip.removeClass('fade top bottom left right in')
+ 
+--- a/js/tooltip.js
++++ b/js/tooltip.js
+@@ -11,6 +11,137 @@
+ +function ($) {
+   'use strict';
+ 
++  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
++
++  var uriAttrs = [
++    'background',
++    'cite',
++    'href',
++    'itemtype',
++    'longdesc',
++    'poster',
++    'src',
++    'xlink:href'
++  ]
++
++  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
++
++  var DefaultWhitelist = {
++    // Global attributes allowed on any supplied element below.
++    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
++    a: ['target', 'href', 'title', 'rel'],
++    area: [],
++    b: [],
++    br: [],
++    col: [],
++    code: [],
++    div: [],
++    em: [],
++    hr: [],
++    h1: [],
++    h2: [],
++    h3: [],
++    h4: [],
++    h5: [],
++    h6: [],
++    i: [],
++    img: ['src', 'alt', 'title', 'width', 'height'],
++    li: [],
++    ol: [],
++    p: [],
++    pre: [],
++    s: [],
++    small: [],
++    span: [],
++    sub: [],
++    sup: [],
++    strong: [],
++    u: [],
++    ul: []
++  }
++
++  /**
++   * A pattern that recognizes a commonly useful subset of URLs that are safe.
++   *
++   * Shoutout to Angular 7 
https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
++   */
++  var SAFE_URL_PATTERN = 
/^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
++
++  /**
++   * A pattern that matches safe data URLs. Only matches image, video and 
audio types.
++   *
++   * Shoutout to Angular 7 
https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
++   */
++  var DATA_URL_PATTERN = 
/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
++
++  function allowedAttribute(attr, allowedAttributeList) {
++    var attrName = attr.nodeName.toLowerCase()
++
++    if ($.inArray(attrName, allowedAttributeList) !== -1) {
++      if ($.inArray(attrName, uriAttrs) !== -1) {
++        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || 
attr.nodeValue.match(DATA_URL_PATTERN))
++      }
++
++      return true
++    }
++
++    var regExp = $(allowedAttributeList).filter(function (index, value) {
++      return value instanceof RegExp
++    })
++
++    // Check if a regular expression validates the attribute.
++    for (var i = 0, l = regExp.length; i < l; i++) {
++      if (attrName.match(regExp[i])) {
++        return true
++      }
++    }
++
++    return false
++  }
++
++  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
++    if (unsafeHtml.length === 0) {
++      return unsafeHtml
++    }
++
++    if (sanitizeFn && typeof sanitizeFn === 'function') {
++      return sanitizeFn(unsafeHtml)
++    }
++
++    // IE 8 and below don't support createHTMLDocument
++    if (!document.implementation || 
!document.implementation.createHTMLDocument) {
++      return unsafeHtml
++    }
++
++    var createdDocument = 
document.implementation.createHTMLDocument('sanitization')
++    createdDocument.body.innerHTML = unsafeHtml
++
++    var whitelistKeys = $.map(whiteList, function (el, i) { return i })
++    var elements = $(createdDocument.body).find('*')
++
++    for (var i = 0, len = elements.length; i < len; i++) {
++      var el = elements[i]
++      var elName = el.nodeName.toLowerCase()
++
++      if ($.inArray(elName, whitelistKeys) === -1) {
++        el.parentNode.removeChild(el)
++
++        continue
++      }
++
++      var attributeList = $.map(el.attributes, function (el) { return el })
++      var whitelistedAttributes = [].concat(whiteList['*'] || [], 
whiteList[elName] || [])
++
++      for (var j = 0, len2 = attributeList.length; j < len2; j++) {
++        if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
++          el.removeAttribute(attributeList[j].nodeName)
++        }
++      }
++    }
++
++    return createdDocument.body.innerHTML
++  }
++
+   // TOOLTIP PUBLIC CLASS DEFINITION
+   // ===============================
+ 
+@@ -43,7 +174,10 @@
+     viewport: {
+       selector: 'body',
+       padding: 0
+-    }
++    },
++    sanitize : true,
++    sanitizeFn : null,
++    whiteList : DefaultWhitelist
+   }
+ 
+   Tooltip.prototype.init = function (type, element, options) {
+@@ -84,7 +218,15 @@
+   }
+ 
+   Tooltip.prototype.getOptions = function (options) {
+-    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
++    var dataAttributes = this.$element.data()
++
++    for (var dataAttr in dataAttributes) {
++      if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, 
DISALLOWED_ATTRIBUTES) !== -1) {
++        delete dataAttributes[dataAttr]
++      }
++    }
++
++    options = $.extend({}, this.getDefaults(), dataAttributes, options)
+ 
+     if (options.delay && typeof options.delay == 'number') {
+       options.delay = {
+@@ -93,6 +235,10 @@
+       }
+     }
+ 
++    if (options.sanitize) {
++      options.template = sanitizeHtml(options.template, options.whiteList, 
options.sanitizeFn)
++    }
++
+     return options
+   }
+ 
+@@ -306,7 +452,16 @@
+     var $tip  = this.tip()
+     var title = this.getTitle()
+ 
+-    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
++    if (this.options.html) {
++      if (this.options.sanitize) {
++        title = sanitizeHtml(title, this.options.whiteList, 
this.options.sanitizeFn)
++      }
++
++      $tip.find('.tooltip-inner').html(title)
++    } else {
++      $tip.find('.tooltip-inner').text(title)
++    }
++
+     $tip.removeClass('fade in top bottom left right')
+   }
+ 
+@@ -487,6 +642,9 @@
+     })
+   }
+ 
++  Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
++    return sanitizeHtml(unsafeHtml, this.options.whiteList, 
this.options.sanitizeFn)
++  }
+ 
+   // TOOLTIP PLUGIN DEFINITION
+   // =========================
diff -Nru twitter-bootstrap3-3.3.7+dfsg/debian/patches/series 
twitter-bootstrap3-3.3.7+dfsg/debian/patches/series
--- twitter-bootstrap3-3.3.7+dfsg/debian/patches/series 2019-02-04 
22:25:25.000000000 +0100
+++ twitter-bootstrap3-3.3.7+dfsg/debian/patches/series 2019-02-21 
21:41:25.000000000 +0100
@@ -1 +1,2 @@
 fix-xss-vulnerabilities.patch
+CVE-2019-8331.patch

Reply via email to